1
0
Fork 0

Merge branch 'master' into fixes

Conflicts:
	src/World.h
This commit is contained in:
Tiger Wang 2014-04-24 18:57:25 +01:00
commit 48904ae201
78 changed files with 3146 additions and 565 deletions

View File

@ -2929,9 +2929,10 @@ end
{
-- No sorting is provided for these, they will be output in the same order as defined here
{ FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" },
{ FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
{ FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" },
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
{ FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
{ FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" },
{ FileName = "UsingChunkStays.html", Title = "Using ChunkStays" },
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
}
} ;

View File

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html>
<head>
<title>MCServer - Using ChunkStays</title>
<link rel="stylesheet" type="text/css" href="main.css" />
<link rel="stylesheet" type="text/css" href="prettify.css" />
<script src="prettify.js"></script>
<script src="lang-lua.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id="content">
<h1>Using ChunkStays</h1>
<p>
A plugin may need to manipulate data in arbitrary chunks, and it needs a way to make the server
guarantee that the chunks are available in memory.</p>
<h2>The problem</h2>
<p>
Usually when plugins want to manipulate larger areas of world data, they need to make sure that the
server has the appropriate chunks loaded in the memory. When the data being manipulated can be further
away from the connected players, or the data is being manipulated from a console handler, there is a
real chance that the chunks are not loaded.</p>
<p>
This gets even more important when using the <a href="cBlockArea.html">cBlockArea</a> class for reading
and writing. Those functions will fail when any of the required chunks aren't valid. This means that
either the block area has incomplete data (Read() failed) or incomplete data has been written to the
world (Write() failed). Recovery from this is near impossible - you can't simply read or write again
later, because the world may have changed in the meantime.</p>
<h2>The solution</h2>
<p>
The naive solution would be to monitor chunk loads and unloads, and postpone the operations until all
the chunks are available. This would be quite ineffective and also very soon it would become very
difficult to maintain, if there were multiple code paths requiring this handling.</p>
<p>
An alternate approach has been implemented, accessible through a single (somewhat hidden) function
call: <a href="cWorld.html">cWorld:ChunkStay()</a>. All that this call basically does is, it tells the
server "Load these chunks for me, and call this callback function once you have them all." And the
server does exactly that - it remembers the callback and asks the world loader / generator to provide
the chunks. Once the chunks become available, it calls the callback function for the plugin.</p>
<p>
There are a few gotcha-s, though. If the code that was requesting the read or write had access to some
of the volatile objects, such as <a href="cPlayer.html">cPlayer</a> or
<a href="cEntity.html">cEntity</a> objects, those cannot be accessed by the callback anymore, because
they may have become invalid in the meantime - the player may have disconnected, the entity may have
despawned. So the callback must use the longer way to access such objects, such as calling
<a href="cWorld.html">cWorld:DoWithEntityByID()</a> or
<a href="cWorld.html">cWorld:DoWithPlayer()</a>.</p>
<h2>The example</h2>
<p>
As a simple example, consider a theoretical plugin that allows a player to save the immediate
surroundings of the spawn into a schematic file. The player issues a command to initiate the save, and
the plugin reads a 50 x 50 x 50 block area around the spawn into a cBlockArea and saves it on the disk
as "<PlayerName>_spawn.schematic". When it's done with the saving, it wants to send a message to the
player to let them know the command has succeeded.</p>
<p>
The first attempt shows the naive approach. It simply reads the block area and saves it, then sends the
message. I'll repeat once more, this code is <b>the wrong way</b> to do it!</p>
<pre class="prettyprint lang-lua">
function HandleCommandSaveSpawn(a_Split, a_Player)
-- Get the coords for the spawn:
local SpawnX = a_Player:GetWorld():GetSpawnX()
local SpawnY = a_Player:GetWorld():GetSpawnY()
local SpawnZ = a_Player:GetWorld():GetSpawnZ()
local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25)
Bounds:ClampY(0, 255)
-- Read the area around spawn into a cBlockArea, save to file:
local Area = cBlockArea()
local FileName = a_Player:GetName() .. "_spawn.schematic"
Area:Read(a_Player:GetWorld(), Bounds, cBlockArea.baTypes + cBlockArea.baMetas)
Area:SaveToSchematicFile(FileName)
-- Notify the player:
a_Player:SendMessage(cCompositeChat("The spawn has been saved", mtInfo))
return true
end
</pre>
<p>
Now if the player goes exploring far and uses the command to save their spawn, the chunks aren't
loaded, so the BlockArea reading fails, the BlockArea contains bad data. Note that the plugin fails to
do any error checking and if the area isn't read from the world, it happily saves the incomplete data
and says "hey, everything's right", althought it has just trashed any previous backup of the spawn
schematic with nonsense data.</p>
<hr/>
<p>
The following script uses the ChunkStay method to alleviate chunk-related problems. This is <b>the
right way</b> of doing it:</p>
<pre class="prettyprint lang-lua">
function HandleCommandSaveSpawn(a_Split, a_Player)
-- Get the coords for the spawn:
local SpawnX = a_Player:GetWorld():GetSpawnX()
local SpawnY = a_Player:GetWorld():GetSpawnY()
local SpawnZ = a_Player:GetWorld():GetSpawnZ()
local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25)
Bounds:ClampY(0, 255)
-- Get a list of chunks that we need loaded:
local MinChunkX = math.floor((SpawnX - 25) / 16)
local MaxChunkX = math.ceil ((SpawnX + 25) / 16)
local MinChunkZ = math.floor((SpawnZ - 25) / 16)
local MaxChunkZ = math.ceil ((SpawnZ + 25) / 16)
local Chunks = {}
for x = MinChunkX, MaxChunkX do
for z = MinChunkZ, MaxChunkZ do
table.insert(Chunks, {x, z})
end
end -- for x
-- Store the player's name and world to use in the callback, because the a_Player object may no longer be valid:
local PlayerName = a_Player:GetName()
local World = a_Player:GetWorld()
-- This is the callback that is executed once all the chunks are loaded:
local OnAllChunksAvailable = function()
-- Read the area around spawn into a cBlockArea, save to file:
local Area = cBlockArea()
local FileName = PlayerName .. "_spawn.schematic"
if (Area:Read(World, Bounds, cBlockArea.baTypes + cBlockArea.baMetas)) then
Area:SaveToSchematicFile(FileName)
Msg = cCompositeChat("The spawn has been saved", mtInfo)
else
Msg = cCompositeChat("Cannot save the spawn", mtFailure)
end
-- Notify the player:
-- Note that we cannot use a_Player here, because it may no longer be valid (if the player disconnected before the command completes)
World:DoWithPlayer(PlayerName,
function (a_CBPlayer)
a_CBPlayer:SendMessage(Msg)
end
)
end
-- Ask the server to load our chunks and notify us once it's done:
World:ChunkStay(Chunks, nil, OnAllChunksAvailable)
-- Note that code here may get executed before the callback is called!
-- The ChunkStay says "once you have the chunks", not "wait until you have the chunks"
-- So you can't notify the player here, because the saving needn't have occurred yet.
return true
end
</pre>
<p>
Note that this code does its error checking of the Area:Read() function, and it will not overwrite the
previous file unless it actually has the correct data. If you're wondering how the reading could fail
when we've got the chunks loaded, there's still the issue of free RAM - if the memory for the area
cannot be allocated, it cannot be read even with all the chunks present. So we still do need that
check.</p>
<h2>The conclusion</h2>
<p>
Although it makes the code a little bit longer and is a bit more difficult to grasp at first, the
ChunkStay is a useful technique to add to your repertoire. It is to be used whenever you need access to
chunks that may potentially be inaccessible, and you really need the data.</p>
<p>Possibly the biggest hurdle in using the ChunkStay is the fact that it does its work in the
background, thus invalidating all cPlayer and cEntity objects your function may hold, so you need to
re-acquire them from their IDs and names. This is the penalty for using multi-threaded code.</p>
<script>
prettyPrint();
</script>
</div>
</body>
</html>

View File

@ -39,31 +39,31 @@
<h2>Example</h2>
The Core has the facility to kick players using the web interface. It used the following code for the kicking (inside the webadmin handler):
<pre class="prettyprint lang-lua">
local KickPlayerName = Request.Params["players-kick"]
local FoundPlayerCallback = function(Player)
if (Player:GetName() == KickPlayerName) then
Player:GetClientHandle():Kick("You were kicked from the game!")
end
<pre class="prettyprint lang-lua">
local KickPlayerName = Request.Params["players-kick"]
local FoundPlayerCallback = function(Player)
if (Player:GetName() == KickPlayerName) then
Player:GetClientHandle():Kick("You were kicked from the game!")
end
end
cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
</pre>
The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
<pre class="prettyprint lang-lua">
cRoot:Get():ForEachWorld( -- For each world...
function(World)
World:QueueTask( -- ... queue a task...
function(a_World)
a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
function (a_Player)
a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
end
cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
</pre>
The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
<pre class="prettyprint lang-lua">
cRoot:Get():ForEachWorld( -- For each world...
function(World)
World:QueueTask( -- ... queue a task...
function(a_World)
a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
function (a_Player)
a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
end
)
end
)
end
)
</pre>
)
end
)
end
)
</pre>
<script>
prettyPrint();
</script>

View File

@ -47,12 +47,13 @@ AttackDamage=4.0
SightDistance=25.0
MaxHealth=40
[Zombiepigman]
[ZombiePigman]
AttackRange=2.0
AttackRate=1
AttackDamage=7.0
SightDistance=25.0
MaxHealth=20
IsFireproof=1
[Cavespider]
AttackRange=2.0
@ -74,6 +75,7 @@ AttackRate=1
AttackDamage=0.0
SightDistance=50.0
MaxHealth=10
IsFireproof=1
[Silverfish]
AttackRange=2.0
@ -115,6 +117,7 @@ AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=20
IsFireproof=1
[Villager]
AttackRange=2.0
@ -122,6 +125,7 @@ AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=20
IsFireproof=0
[Witch]
AttackRange=2.0
@ -145,12 +149,13 @@ AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Magmacube]
[MagmaCube]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=16
IsFireproof=1
[Horse]
AttackRange=2.0

View File

@ -30,7 +30,7 @@ if "a%ftpsite%" == "a" (
cd MCServer
copy /Y settings_apidump.ini settings.ini
echo stop | MCServer
echo api | MCServer
cd ..

View File

@ -46,10 +46,6 @@ macro(set_flags)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
add_flags_cxx("-pthread")
endif()
@ -60,10 +56,6 @@ macro(set_flags)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
endif()
# We use a signed char (fixes #640 on RasPi)

View File

@ -0,0 +1,116 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "BeaconEntity.h"
#include "../BlockArea.h"
cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World)
{
}
int cBeaconEntity::GetPyramidLevel(void)
{
cBlockArea Area;
int MinY = GetPosY() - 4;
if (MinY < 0)
{
MinY = 0;
}
int MaxY = GetPosY() - 1;
if (MaxY < 0)
{
MaxY = 0;
}
Area.Read(
m_World,
GetPosX() - 4, GetPosX() + 4,
MinY, MaxY,
GetPosZ() - 4, GetPosZ() + 4,
cBlockArea::baTypes
);
int Layer = 1;
int MiddleXZ = 4;
for (int Y = Area.GetSizeY() - 1; Y > 0; Y--)
{
for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
{
for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
{
if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
{
return Layer - 1;
}
}
}
Layer++;
}
return Layer - 1;
}
bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
{
case E_BLOCK_DIAMOND_BLOCK:
case E_BLOCK_GOLD_BLOCK:
case E_BLOCK_IRON_BLOCK:
case E_BLOCK_EMERALD_BLOCK:
{
return true;
}
}
return false;
}
bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
return false;
}
void cBeaconEntity::SaveToJson(Json::Value& a_Value)
{
}
void cBeaconEntity::SendTo(cClientHandle & a_Client)
{
}
void cBeaconEntity::UsedBy(cPlayer * a_Player)
{
}

View File

@ -0,0 +1,44 @@
#pragma once
#include "BlockEntity.h"
namespace Json
{
class Value;
}
class cBeaconEntity :
public cBlockEntity
{
typedef cBlockEntity super;
public:
/** The initial constructor */
cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
/** Returns the amount of layers the pyramid below the beacon has. */
int GetPyramidLevel(void);
/** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */
static bool IsMineralBlock(BLOCKTYPE a_BlockType);
// cBlockEntity overrides:
virtual void SaveToJson(Json::Value& a_Value ) override;
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override;
} ;

View File

@ -4,6 +4,7 @@
// Implements the cBlockEntity class that is the common ancestor for all block entities
#include "Globals.h"
#include "BeaconEntity.h"
#include "BlockEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
@ -26,6 +27,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{
switch (a_BlockType)
{
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);

View File

@ -128,10 +128,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
{
DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0);
m_Contents.SetSlot(a_SlotNum, m_Contents.GetSlot(a_SlotNum).m_ItemType, m_Contents.GetSlot(a_SlotNum).m_ItemCount, m_Contents.GetSlot(a_SlotNum).m_ItemDamage + 1);
// If the durability has run out destroy the item.
if (m_Contents.GetSlot(a_SlotNum).m_ItemDamage > 64)
{
bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1);
if (ItemBroke)
{
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
}

View File

@ -413,19 +413,20 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return false;
}
if (m_Contents.GetSlot(fsOutput).IsEmpty())
const cItem & Slot = m_Contents.GetSlot(fsOutput);
if (Slot.IsEmpty())
{
// The output is empty, can cook
return true;
}
if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
if (!Slot.IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;
}
if (m_Contents.GetSlot(fsOutput).IsFullStack())
if (Slot.IsFullStack())
{
// Cannot add any more items to the output slot
return false;

View File

@ -234,24 +234,27 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool TrySuckPickupIn(cPickup * a_Pickup)
{
cItem & Item = a_Pickup->GetItem();
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
if (m_Contents.IsSlotEmpty(i))
{
m_bFoundPickupsAbove = true;
m_Contents.SetSlot(i, a_Pickup->GetItem());
m_Contents.SetSlot(i, Item);
a_Pickup->Destroy(); // Kill pickup
return true;
}
else if (m_Contents.GetSlot(i).IsEqual(a_Pickup->GetItem()) && !m_Contents.GetSlot(i).IsFullStack())
else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack())
{
m_bFoundPickupsAbove = true;
int PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
a_Pickup->GetItem().m_ItemCount -= m_Contents.ChangeSlotCount(i, a_Pickup->GetItem().m_ItemCount) - PreviousCount; // Set count to however many items were added
if (a_Pickup->GetItem().IsEmpty())
Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added
if (Item.IsEmpty())
{
a_Pickup->Destroy(); // Kill pickup if all items were added
}

View File

@ -56,6 +56,7 @@ public:
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
// FIXME: This is unreachable, as the condition is the same as the above one
a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}

View File

@ -0,0 +1,37 @@
#pragma once
#include "BlockHandler.h"
#include "../UI/Window.h"
#include "../Entities/Player.h"
class cBlockEnchantmentTableHandler :
public cBlockHandler
{
public:
cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ);
a_Player->OpenWindow(Window);
}
virtual bool IsUseable(void) override
{
return true;
}
};

View File

@ -25,6 +25,7 @@
#include "BlockDirt.h"
#include "BlockDoor.h"
#include "BlockDropSpenser.h"
#include "BlockEnchantmentTable.h"
#include "BlockEnderchest.h"
#include "BlockEntity.h"
#include "BlockFarmland.h"
@ -119,6 +120,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_DOUBLE_WOODEN_SLAB: return new cBlockDoubleSlabHandler (a_BlockType);
case E_BLOCK_DROPPER: return new cBlockDropSpenserHandler (a_BlockType);
case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType);
case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType);
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( );
case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);

View File

@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_NEW_LOG: return true; \
}

View File

@ -141,7 +141,7 @@ public:
NIBBLETYPE Meta = 0;
char RailsCnt = 0;
bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP
memset(Neighbors, false, sizeof(Neighbors));
memset(Neighbors, 0, sizeof(Neighbors));
Neighbors[0] = (IsUnstable(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN));
Neighbors[1] = (IsUnstable(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN));
Neighbors[2] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN));

View File

@ -288,7 +288,7 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d &
Coeff = c;
}
c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Max.y);
if ((c >= 0) && (c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
{
Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM;
Coeff = c;

View File

@ -452,7 +452,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill)
{
cMonster& Monster = (cMonster&)(**itr);
currentPosition = Monster.GetPosition();
for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++)
for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); ++itr2)
{
toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength());
}
@ -600,7 +600,7 @@ void cChunk::Tick(float a_Dt)
delete ToDelete;
continue;
}
itr++;
++itr;
} // for itr - m_Entitites[]
// If any entity moved out of the chunk, move it to the neighbor:
@ -1299,6 +1299,7 @@ void cChunk::CreateBlockEntities(void)
BLOCKTYPE BlockType = cChunkDef::GetBlock(m_BlockTypes, x, y, z);
switch (BlockType)
{
case E_BLOCK_BEACON:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
@ -1429,6 +1430,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
// If the new block is a block entity, create the entity object:
switch (a_BlockType)
{
case E_BLOCK_BEACON:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:

View File

@ -382,14 +382,14 @@ private:
struct sSetBlockQueueItem
{
Int64 m_Tick;
int m_RelX, m_RelY, m_RelZ;
BLOCKTYPE m_BlockType;
NIBBLETYPE m_BlockMeta;
Int64 m_Tick;
BLOCKTYPE m_PreviousType;
sSetBlockQueueItem(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) :
m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_Tick(a_Tick), m_PreviousType(a_PreviousBlockType)
m_Tick(a_Tick), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_PreviousType(a_PreviousBlockType)
{
}
} ;

View File

@ -1656,7 +1656,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.",
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
@ -1691,7 +1691,7 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return;
}
@ -1723,7 +1723,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -1973,7 +1973,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -1988,7 +1988,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback &
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2003,7 +2003,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2018,7 +2018,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2033,7 +2033,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2048,7 +2048,7 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2066,7 +2066,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2084,7 +2084,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2102,7 +2102,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2120,7 +2120,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2138,7 +2138,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2156,7 +2156,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2173,7 +2173,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2190,7 +2190,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2208,7 +2208,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2226,7 +2226,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}
@ -2244,7 +2244,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString &
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
if ((Chunk == NULL) || !Chunk->IsValid())
{
return false;
}

View File

@ -453,14 +453,16 @@ void cClientHandle::HandlePing(void)
{
// Somebody tries to retrieve information about the server
AString Reply;
const cServer & Server = *cRoot::Get()->GetServer();
Printf(Reply, "%s%s%i%s%i",
cRoot::Get()->GetServer()->GetDescription().c_str(),
Server.GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetNumPlayers(),
Server.GetNumPlayers(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetMaxPlayers()
Server.GetMaxPlayers()
);
Kick(Reply.c_str());
Kick(Reply);
}
@ -1216,8 +1218,8 @@ void cClientHandle::HandleChat(const AString & a_Message)
Color = AString("@") + Color[2];
}
else
{
Color.empty();
{
Color.clear();
}
Msg.AddTextPart(AString("<") + m_Player->GetName() + "> ", Color);
Msg.ParseText(a_Message);
@ -2729,4 +2731,27 @@ void cClientHandle::SocketClosed(void)
void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment)
{
cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow();
cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player);
int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment);
if (Item.EnchantByXPLevels(BaseEnchantmentLevel))
{
if (m_Player->IsGameModeCreative() || m_Player->DeltaExperience(-m_Player->XpForLevel(BaseEnchantmentLevel)) >= 0)
{
Window->m_SlotArea->SetSlot(0, *m_Player, Item);
Window->SendSlot(*m_Player, Window->m_SlotArea, 0);
Window->BroadcastWholeWindow();
Window->SetProperty(0, 0, *m_Player);
Window->SetProperty(1, 0, *m_Player);
Window->SetProperty(2, 0, *m_Player);
}
}
}

View File

@ -18,6 +18,8 @@
#include "ByteBuffer.h"
#include "Scoreboard.h"
#include "Map.h"
#include "Enchantments.h"
#include "UI/SlotArea.h"
@ -244,6 +246,9 @@ public:
/** Called when the player moves into a different world; queues sreaming the new chunks */
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
/** Called when the player will enchant a Item */
void HandleEnchantItem(Byte & WindowID, Byte & Enchantment);
private:
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */

View File

@ -661,14 +661,16 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
ASSERT(itrS->x + a_OffsetX < a_GridWidth);
ASSERT(itrS->y + a_OffsetY < a_GridHeight);
int GridID = (itrS->x + a_OffsetX) + a_GridStride * (itrS->y + a_OffsetY);
const cItem & Item = itrS->m_Item;
if (
(itrS->x >= a_GridWidth) ||
(itrS->y >= a_GridHeight) ||
(itrS->m_Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type?
(itrS->m_Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items
(Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type?
(Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items
(
(itrS->m_Item.m_ItemDamage > 0) && // should compare damage values?
(itrS->m_Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage)
(Item.m_ItemDamage > 0) && // should compare damage values?
(Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage)
)
)
{
@ -824,7 +826,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe
case E_ITEM_DYE:
{
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye((NIBBLETYPE)(a_CraftingGrid[GridID].m_ItemDamage & 0x0f)));
break;
}
case E_ITEM_GUNPOWDER: break;

View File

@ -206,7 +206,7 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte
ASSERT(!"Invalid a_DecryptedMaxLength!");
return -1;
}
if (a_EncryptedMaxLength < m_Rsa.len)
if (a_PlainLength < m_Rsa.len)
{
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)

View File

@ -112,18 +112,21 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
ASSERT(!"Unknown world in cDeadlockDetect");
return;
}
if (itr->second.m_Age == a_Age)
cDeadlockDetect::sWorldAge & WorldAge = itr->second;
if (WorldAge.m_Age == a_Age)
{
itr->second.m_NumCyclesSame += 1;
if (itr->second.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
WorldAge.m_NumCyclesSame += 1;
if (WorldAge.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
{
DeadlockDetected();
}
}
else
{
itr->second.m_Age = a_Age;
itr->second.m_NumCyclesSame = 0;
WorldAge.m_Age = a_Age;
WorldAge.m_NumCyclesSame = 0;
}
}

View File

@ -5,6 +5,7 @@
#include "Globals.h"
#include "Enchantments.h"
#include "WorldStorage/FastNBT.h"
#include "FastRandom.h"
@ -28,6 +29,18 @@ cEnchantments::cEnchantments(const AString & a_StringSpec)
void cEnchantments::Add(const cEnchantments & a_Other)
{
for (cEnchantments::cMap::const_iterator itr = a_Other.m_Enchantments.begin(), end = a_Other.m_Enchantments.end(); itr != end; ++itr)
{
SetLevel(itr->first, itr->second);
} // for itr - a_Other.m_Enchantments[]
}
void cEnchantments::AddFromString(const AString & a_StringSpec)
{
// Add enchantments in the stringspec; if a specified enchantment already exists, overwrites it
@ -218,8 +231,782 @@ bool cEnchantments::operator !=(const cEnchantments & a_Other) const
void cEnchantments::AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel)
{
if (ItemCategory::IsSword(a_ItemType))
{
// Sharpness
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4);
}
else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1);
}
// Smite
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1);
}
// Bane of Arthropods
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1);
}
// Knockback
if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1);
}
// Fire Aspect
if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1);
}
// Looting
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1);
}
}
else if (ItemCategory::IsTool(a_ItemType))
{
// Efficiency
if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1);
}
// Silk Touch
if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1);
}
// Fortune
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1);
}
}
else if (ItemCategory::IsArmor(a_ItemType))
{
// Protection
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4);
}
else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1);
}
// Fire Protection
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4);
}
else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3);
}
else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1);
}
// Blast Protection
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1);
}
// Projectile Protection
if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3);
}
else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2);
}
else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1);
}
// Thorns
if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3);
}
else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1);
}
if (ItemCategory::IsHelmet(a_ItemType))
{
// Respiration
if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3);
}
else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1);
}
// Aqua Affinity
if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1);
}
}
else if (ItemCategory::IsBoots(a_ItemType))
{
// Feather Fall
if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4);
}
else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1);
}
}
}
else if (a_ItemType == E_ITEM_BOW)
{
// Power
if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1);
}
// Punch
if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1);
}
// Flame and Infinity
if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1);
}
}
else if (a_ItemType == E_ITEM_FISHING_ROD)
{
// Luck of the Sea and Lure
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1);
}
}
else if (a_ItemType == E_ITEM_BOOK)
{
// All Enchantments
// Sharpness
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4);
}
else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1);
}
// Smite
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1);
}
// Bane of Arthropods
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1);
}
// Knockback
if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1);
}
// Fire Aspect
if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1);
}
// Looting
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1);
}
// Efficiency
if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1);
}
// Silk Touch
if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1);
}
// Fortune
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1);
}
// Protection
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4);
}
else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1);
}
// Fire Protection
if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4);
}
else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3);
}
else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1);
}
// Blast Protection
if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1);
}
// Projectile Protection
if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3);
}
else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2);
}
else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1);
}
// Thorns
if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3);
}
else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1);
}
// Respiration
if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3);
}
else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1);
}
// Aqua Affinity
if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1);
}
// Feather Fall
if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4);
}
else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1);
}
// Power
if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4);
}
else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3);
}
else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2);
}
else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16))
{
AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1);
}
// Punch
if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2);
}
else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1);
}
// Flame and Infinity
if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1);
}
// Luck of the Sea and Lure
if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3);
}
else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2);
}
else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65))
{
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1);
AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1);
}
}
// Unbreaking
if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 3);
}
else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 63))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 2);
}
else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55))
{
AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 1);
}
}
void cEnchantments::AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel)
{
cWeightedEnchantment weightedenchantment;
weightedenchantment.m_Weight = a_Weight;
cEnchantments enchantment;
enchantment.SetLevel(a_EnchantmentID, a_EnchantmentLevel);
weightedenchantment.m_Enchantments = enchantment;
a_Enchantments.push_back(weightedenchantment);
}
void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID)
{
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
{
if ((*it).m_Enchantments.GetLevel(a_EnchantmentID) > 0)
{
a_Enchantments.erase(it);
break;
}
}
}
void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment)
{
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
{
if ((*it).m_Enchantments == a_Enchantment)
{
a_Enchantments.erase(it);
break;
}
}
}
void cEnchantments::CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment)
{
if (a_FirstEnchantment.GetLevel(cEnchantments::enchProtection) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFireProtection) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBlastProtection) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchProjectileProtection) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSharpness) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSmite) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBaneOfArthropods) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness);
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSilkTouch) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFortune);
}
else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFortune) > 0)
{
RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSilkTouch);
}
}
cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments)
{
cFastRandom Random;
int AllWeights = 0;
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
{
AllWeights += (*it).m_Weight;
}
int RandomNumber = Random.GenerateRandomInteger(0, AllWeights - 1);
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
{
RandomNumber -= (*it).m_Weight;
if (RandomNumber < 0)
{
return (*it).m_Enchantments;
}
}
return cEnchantments();
}

View File

@ -8,6 +8,7 @@
#pragma once
#include "Defines.h"
#include "WorldStorage/EnchantmentSerializer.h"
@ -18,6 +19,11 @@ class cFastNBTWriter;
class cParsedNBT;
// fwd:
struct cWeightedEnchantment;
typedef std::vector<cWeightedEnchantment> cWeightedEnchantments;
@ -28,11 +34,14 @@ mapping each enchantment's id onto its level. ID may be either a number or the e
Level value of 0 means no such enchantment, and it will not be stored in the m_Enchantments.
Serialization will never put zero-level enchantments into the stringspec and will always use numeric IDs.
*/
// tolua_begin
class cEnchantments
{
public:
/// Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs )
/** Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs )
*/
enum
{
@ -61,56 +70,87 @@ public:
enchLuckOfTheSea = 61,
enchLure = 62,
} ;
/// Creates an empty enchantments container
/** Creates an empty enchantments container */
cEnchantments(void);
/// Creates an enchantments container filled with enchantments parsed from stringspec
/** Creates an enchantments container filled with enchantments parsed from stringspec */
cEnchantments(const AString & a_StringSpec);
/// Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it
/** Adds the enchantments contained in a_Other into this object.
Existing enchantments are preserved, unless a_Other specifies a different level, in which case the level is changed. */
void Add(const cEnchantments & a_Other);
/** Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it */
void AddFromString(const AString & a_StringSpec);
/// Serializes all the enchantments into a string
/** Serializes all the enchantments into a string */
AString ToString(void) const;
/// Returns the level for the specified enchantment; 0 if not stored
/** Returns the level for the specified enchantment; 0 if not stored */
int GetLevel(int a_EnchantmentID) const;
/// Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0
/** Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0 */
void SetLevel(int a_EnchantmentID, int a_Level);
/// Removes all enchantments
/** Removes all enchantments */
void Clear(void);
/// Returns true if there are no enchantments
/** Returns true if there are no enchantments */
bool IsEmpty(void) const;
/// Converts enchantment name to the numeric representation; returns -1 if enchantment name not found; case insensitive
/** Converts enchantment name to the numeric representation; returns -1 if enchantment name not found; case insensitive */
static int StringToEnchantmentID(const AString & a_EnchantmentName);
/// Returns true if a_Other contains exactly the same enchantments and levels
/** Returns true if a_Other contains exactly the same enchantments and levels */
bool operator ==(const cEnchantments & a_Other) const;
// tolua_end
/** Add enchantment weights from item to the vector */
static void AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel);
/** Add a enchantment with weight to the vector */
static void AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel);
/// Returns true if a_Other doesn't contain exactly the same enchantments and levels
/** Remove the entire enchantment (with weight) from the vector */
static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID);
/** Remove the entire enchantment (with weight) from the vector */
static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment);
/** Check enchantment conflicts from enchantments from the vector */
static void CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment);
/** Gets random enchantment from Vector and returns it */
static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments);
/** Returns true if a_Other doesn't contain exactly the same enchantments and levels */
bool operator !=(const cEnchantments & a_Other) const;
/// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments")
/** Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") */
friend void EnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName);
/// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments)
/** Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) */
friend void EnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx);
protected:
/// Maps enchantment ID -> enchantment level
/** Maps enchantment ID -> enchantment level */
typedef std::map<int, int> cMap;
/// Currently stored enchantments
/** Currently stored enchantments */
cMap m_Enchantments;
} ; // tolua_export
// Define the cWeightedEnchantment struct for the Enchanting System to store the EnchantmentWeights:
struct cWeightedEnchantment
{
int m_Weight;
cEnchantments m_Enchantments;
};

View File

@ -38,6 +38,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_IsInitialized(false)
, m_EntityType(a_EntityType)
, m_World(NULL)
, m_IsFireproof(false)
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
@ -796,7 +797,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastBurnDamage++;
if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
{
TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
if (!m_IsFireproof)
{
TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
}
m_TicksSinceLastBurnDamage = 0;
}
m_TicksLeftBurning--;
@ -864,7 +868,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastLavaDamage++;
if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE)
{
TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
if (!m_IsFireproof)
{
TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
}
m_TicksSinceLastLavaDamage = 0;
}
}
@ -882,7 +889,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastFireDamage++;
if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
{
TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
if (!m_IsFireproof)
{
TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
}
m_TicksSinceLastFireDamage = 0;
}
}
@ -1041,6 +1051,16 @@ void cEntity::SetMaxHealth(int a_MaxHealth)
/// Sets whether the entity is fireproof
void cEntity::SetIsFireproof(bool a_IsFireproof)
{
m_IsFireproof = a_IsFireproof;
}
/// Puts the entity on fire for the specified amount of ticks
void cEntity::StartBurning(int a_TicksLeftBurning)
{

View File

@ -329,6 +329,11 @@ public:
int GetMaxHealth(void) const { return m_MaxHealth; }
/// Sets whether the entity is fireproof
void SetIsFireproof(bool a_IsFireproof);
bool IsFireproof(void) const { return m_IsFireproof; }
/// Puts the entity on fire for the specified amount of ticks
void StartBurning(int a_TicksLeftBurning);
@ -432,6 +437,9 @@ protected:
cWorld * m_World;
/// Whether the entity is capable of taking fire or lava damage.
bool m_IsFireproof;
/// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire())
int m_TicksSinceLastBurnDamage;

View File

@ -795,7 +795,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT);
BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
if (
(!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||

View File

@ -82,9 +82,10 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
if (!LoadFromDisk())
{
m_Inventory.Clear();
SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX());
SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY());
SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ());
cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld();
SetPosX(DefaultWorld->GetSpawnX());
SetPosY(DefaultWorld->GetSpawnY());
SetPosZ(DefaultWorld->GetSpawnZ());
LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
@ -1159,9 +1160,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
void cPlayer::ForceSetSpeed(Vector3d a_Direction)
void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
{
SetSpeed(a_Direction);
SetSpeed(a_Speed);
m_ClientHandle->SendEntityVelocity(*this);
}

View File

@ -181,7 +181,7 @@ public:
void LoginSetGameMode(eGameMode a_GameMode);
/** Forces the player to move in the given direction. */
void ForceSetSpeed(Vector3d a_Direction); // tolua_export
void ForceSetSpeed(const Vector3d & a_Speed); // tolua_export
/** Tries to move to a new position, with attachment-related checks (y == -999) */
void MoveTo(const Vector3d & a_NewPos); // tolua_export

View File

@ -172,3 +172,13 @@ float cFastRandom::NextFloat(float a_Range, int a_Salt)
int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
{
cFastRandom Random;
return Random.NextInt(a_End - a_Begin + 1) + a_Begin;
}

View File

@ -43,6 +43,9 @@ public:
/// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness
float NextFloat(float a_Range, int a_Salt);
/** Returns a random int in the range [a_Begin .. a_End] */
int GenerateRandomInteger(int a_Begin, int a_End);
protected:
int m_Seed;

View File

@ -56,7 +56,6 @@ void cFurnaceRecipe::ReloadRecipes(void)
std::ifstream f;
char a_File[] = "furnace.txt";
f.open(a_File, std::ios::in);
std::string input;
if (!f.good())
{

View File

@ -200,13 +200,14 @@ void cCaveTunnel::Randomize(cNoise & a_Noise)
for (int i = 0; i < 4; i++)
{
// For each already present point, insert a point in between it and its predecessor, shifted randomly.
int PrevX = m_Points.front().m_BlockX;
int PrevY = m_Points.front().m_BlockY;
int PrevZ = m_Points.front().m_BlockZ;
int PrevR = m_Points.front().m_Radius;
cCaveDefPoint & Point = m_Points.front();
int PrevX = Point.m_BlockX;
int PrevY = Point.m_BlockY;
int PrevZ = Point.m_BlockZ;
int PrevR = Point.m_Radius;
cCaveDefPoints Pts;
Pts.reserve(m_Points.size() * 2 + 1);
Pts.push_back(m_Points.front());
Pts.push_back(Point);
for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr)
{
int Random = a_Noise.IntNoise3DInt(PrevX, PrevY, PrevZ + i) / 11;
@ -244,11 +245,12 @@ bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints &
a_Dst.clear();
a_Dst.reserve(Num * 2 + 2);
cCaveDefPoints::const_iterator itr = a_Src.begin() + 1;
a_Dst.push_back(a_Src.front());
int PrevX = a_Src.front().m_BlockX;
int PrevY = a_Src.front().m_BlockY;
int PrevZ = a_Src.front().m_BlockZ;
int PrevR = a_Src.front().m_Radius;
const cCaveDefPoint & Source = a_Src.front();
a_Dst.push_back(Source);
int PrevX = Source.m_BlockX;
int PrevY = Source.m_BlockY;
int PrevZ = Source.m_BlockZ;
int PrevR = Source.m_Radius;
for (int i = 0; i <= Num; ++i, ++itr)
{
int dx = itr->m_BlockX - PrevX;
@ -310,9 +312,10 @@ void cCaveTunnel::FinishLinear(void)
std::swap(Pts, m_Points);
m_Points.reserve(Pts.size() * 3);
int PrevX = Pts.front().m_BlockX;
int PrevY = Pts.front().m_BlockY;
int PrevZ = Pts.front().m_BlockZ;
cCaveDefPoint & PrevPoint = Pts.front();
int PrevX = PrevPoint.m_BlockX;
int PrevY = PrevPoint.m_BlockY;
int PrevZ = PrevPoint.m_BlockZ;
for (cCaveDefPoints::const_iterator itr = Pts.begin() + 1, end = Pts.end(); itr != end; ++itr)
{
int x1 = itr->m_BlockX;
@ -433,9 +436,10 @@ void cCaveTunnel::FinishLinear(void)
void cCaveTunnel::CalcBoundingBox(void)
{
m_MinBlockX = m_MaxBlockX = m_Points.front().m_BlockX;
m_MinBlockY = m_MaxBlockY = m_Points.front().m_BlockY;
m_MinBlockZ = m_MaxBlockZ = m_Points.front().m_BlockZ;
cCaveDefPoint & Point = m_Points.front();
m_MinBlockX = m_MaxBlockX = Point.m_BlockX;
m_MinBlockY = m_MaxBlockY = Point.m_BlockY;
m_MinBlockZ = m_MaxBlockZ = Point.m_BlockZ;
for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr)
{
m_MinBlockX = std::min(m_MinBlockX, itr->m_BlockX - itr->m_Radius);

View File

@ -23,6 +23,10 @@ static const cPrefab::sDef g_TestPrefabDef =
// Size:
7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
// Hitbox (relative to bounding box):
0, 0, 0, // MinX, MinY, MinZ
6, 5, 6, // MaxX, MaxY, MaxZ
// Block definitions:
".: 0: 0\n" /* 0 */
"a:112: 0\n" /* netherbrick */
@ -115,7 +119,10 @@ static cPrefab g_TestPrefab(g_TestPrefabDef);
cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
m_HitBox(
a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ,
a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ
),
m_AllowedRotations(a_Def.m_AllowedRotations),
m_MergeStrategy(a_Def.m_MergeStrategy),
m_ShouldExtendFloor(a_Def.m_ShouldExtendFloor),

View File

@ -38,6 +38,10 @@ public:
int m_SizeY;
int m_SizeZ;
/** The hitbox used for collision-checking between prefabs. Relative to the bounds. */
int m_HitboxMinX, m_HitboxMinY, m_HitboxMinZ;
int m_HitboxMaxX, m_HitboxMaxY, m_HitboxMaxZ;
/** The mapping between characters in m_Image and the blocktype / blockmeta.
Format: "Char: BlockType: BlockMeta \n Char: BlockType : BlockMeta \n ..." */
const char * m_CharMap;
@ -114,7 +118,7 @@ protected:
/** The size of the prefab */
Vector3i m_Size;
/** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
/** The hitbox used for collision-checking between prefabs. */
cCuboid m_HitBox;
/** The connectors through which the piece connects to other pieces */

File diff suppressed because it is too large Load Diff

View File

@ -269,7 +269,7 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block
int CenterZ = a_BlockZ + OffsetZ;
// Get the base angle in which the ravine "axis" goes:
float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * 3.141592653);
float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * M_PI);
float xc = sin(Angle);
float zc = cos(Angle);
@ -311,12 +311,13 @@ void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cR
a_Dst.clear();
a_Dst.reserve(Num * 2 + 2);
cRavDefPoints::const_iterator itr = a_Src.begin() + 1;
a_Dst.push_back(a_Src.front());
int PrevX = a_Src.front().m_BlockX;
int PrevZ = a_Src.front().m_BlockZ;
int PrevR = a_Src.front().m_Radius;
int PrevT = a_Src.front().m_Top;
int PrevB = a_Src.front().m_Bottom;
const cRavDefPoint & Source = a_Src.front();
a_Dst.push_back(Source);
int PrevX = Source.m_BlockX;
int PrevZ = Source.m_BlockZ;
int PrevR = Source.m_Radius;
int PrevT = Source.m_Top;
int PrevB = Source.m_Bottom;
for (int i = 0; i <= Num; ++i, ++itr)
{
int dx = itr->m_BlockX - PrevX;

View File

@ -7,7 +7,7 @@
void cGroup::AddCommand( AString a_Command )
void cGroup::AddCommand( const AString & a_Command )
{
m_Commands[ a_Command ] = true;
}
@ -16,7 +16,7 @@ void cGroup::AddCommand( AString a_Command )
void cGroup::AddPermission( AString a_Permission )
void cGroup::AddPermission( const AString & a_Permission )
{
m_Permissions[ a_Permission ] = true;
}

View File

@ -11,11 +11,11 @@ public: // tolua_export
cGroup() {}
~cGroup() {}
void SetName( AString a_Name ) { m_Name = a_Name; } // tolua_export
void SetName( const AString & a_Name ) { m_Name = a_Name; } // tolua_export
const AString & GetName() const { return m_Name; } // tolua_export
void SetColor( AString a_Color ) { m_Color = a_Color; } // tolua_export
void AddCommand( AString a_Command ); // tolua_export
void AddPermission( AString a_Permission ); // tolua_export
void SetColor( const AString & a_Color ) { m_Color = a_Color; } // tolua_export
void AddCommand( const AString & a_Command ); // tolua_export
void AddPermission( const AString & a_Permission ); // tolua_export
void InheritFrom( cGroup* a_Group ); // tolua_export
typedef std::map< AString, bool > PermissionMap;

View File

@ -5,6 +5,8 @@
#include "json/json.h"
#include "Items/ItemHandler.h"
#include "FastRandom.h"
@ -196,9 +198,6 @@ bool cItem::IsEnchantable(short item)
return true;
if ((item >= 298) && (item <= 317))
return true;
if ((item >= 290) && (item <= 294))
return true;
if ((item == 346) || (item == 359) || (item == 261))
return true;
@ -209,6 +208,157 @@ bool cItem::IsEnchantable(short item)
int cItem::GetEnchantability()
{
int Enchantability = 0;
switch (m_ItemType)
{
case E_ITEM_WOODEN_SWORD: Enchantability = 15; break;
case E_ITEM_WOODEN_PICKAXE: Enchantability = 15; break;
case E_ITEM_WOODEN_SHOVEL: Enchantability = 15; break;
case E_ITEM_WOODEN_AXE: Enchantability = 15; break;
case E_ITEM_WOODEN_HOE: Enchantability = 15; break;
case E_ITEM_LEATHER_CAP: Enchantability = 15; break;
case E_ITEM_LEATHER_TUNIC: Enchantability = 15; break;
case E_ITEM_LEATHER_PANTS: Enchantability = 15; break;
case E_ITEM_LEATHER_BOOTS: Enchantability = 15; break;
case E_ITEM_STONE_SWORD: Enchantability = 5; break;
case E_ITEM_STONE_PICKAXE: Enchantability = 5; break;
case E_ITEM_STONE_SHOVEL: Enchantability = 5; break;
case E_ITEM_STONE_AXE: Enchantability = 5; break;
case E_ITEM_STONE_HOE: Enchantability = 5; break;
case E_ITEM_IRON_HELMET: Enchantability = 9; break;
case E_ITEM_IRON_CHESTPLATE: Enchantability = 9; break;
case E_ITEM_IRON_LEGGINGS: Enchantability = 9; break;
case E_ITEM_IRON_BOOTS: Enchantability = 9; break;
case E_ITEM_IRON_SWORD: Enchantability = 14; break;
case E_ITEM_IRON_PICKAXE: Enchantability = 14; break;
case E_ITEM_IRON_SHOVEL: Enchantability = 14; break;
case E_ITEM_IRON_AXE: Enchantability = 14; break;
case E_ITEM_IRON_HOE: Enchantability = 14; break;
case E_ITEM_CHAIN_HELMET: Enchantability = 12; break;
case E_ITEM_CHAIN_CHESTPLATE: Enchantability = 12; break;
case E_ITEM_CHAIN_LEGGINGS: Enchantability = 12; break;
case E_ITEM_CHAIN_BOOTS: Enchantability = 12; break;
case E_ITEM_DIAMOND_HELMET: Enchantability = 10; break;
case E_ITEM_DIAMOND_CHESTPLATE: Enchantability = 10; break;
case E_ITEM_DIAMOND_LEGGINGS: Enchantability = 10; break;
case E_ITEM_DIAMOND_BOOTS: Enchantability = 10; break;
case E_ITEM_DIAMOND_SWORD: Enchantability = 10; break;
case E_ITEM_DIAMOND_PICKAXE: Enchantability = 10; break;
case E_ITEM_DIAMOND_SHOVEL: Enchantability = 10; break;
case E_ITEM_DIAMOND_AXE: Enchantability = 10; break;
case E_ITEM_DIAMOND_HOE: Enchantability = 10; break;
case E_ITEM_GOLD_HELMET: Enchantability = 25; break;
case E_ITEM_GOLD_CHESTPLATE: Enchantability = 25; break;
case E_ITEM_GOLD_LEGGINGS: Enchantability = 25; break;
case E_ITEM_GOLD_BOOTS: Enchantability = 25; break;
case E_ITEM_GOLD_SWORD: Enchantability = 22; break;
case E_ITEM_GOLD_PICKAXE: Enchantability = 22; break;
case E_ITEM_GOLD_SHOVEL: Enchantability = 22; break;
case E_ITEM_GOLD_AXE: Enchantability = 22; break;
case E_ITEM_GOLD_HOE: Enchantability = 22; break;
case E_ITEM_FISHING_ROD: Enchantability = 1; break;
case E_ITEM_BOW: Enchantability = 1; break;
case E_ITEM_BOOK: Enchantability = 1; break;
}
return Enchantability;
}
bool cItem::EnchantByXPLevels(int a_NumXPLevels)
{
if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK))
{
return false;
}
int Enchantability = GetEnchantability();
cFastRandom Random;
int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1;
float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F;
int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F);
cWeightedEnchantments enchantments;
cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel);
if (m_ItemType == E_ITEM_BOOK)
{
m_ItemType = E_ITEM_ENCHANTED_BOOK;
}
cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
m_Enchantments.AddFromString(Enchantment1.ToString());
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1);
// Checking for conflicting enchantments
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1);
float NewEnchantmentLevel = (float)a_NumXPLevels;
// Next Enchantment (Second)
NewEnchantmentLevel = NewEnchantmentLevel / 2;
float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance))
{
return true;
}
cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
m_Enchantments.AddFromString(Enchantment2.ToString());
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2);
// Checking for conflicting enchantments
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2);
// Next Enchantment (Third)
NewEnchantmentLevel = NewEnchantmentLevel / 2;
float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance))
{
return true;
}
cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
m_Enchantments.AddFromString(Enchantment3.ToString());
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3);
// Checking for conflicting enchantments
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3);
// Next Enchantment (Fourth)
NewEnchantmentLevel = NewEnchantmentLevel / 2;
float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance))
{
return true;
}
cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
m_Enchantments.AddFromString(Enchantment4.ToString());
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cItems:

View File

@ -175,6 +175,13 @@ public:
/** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */
static bool IsEnchantable(short a_ItemType); // tolua_export
/** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */
int GetEnchantability(); // tolua_export
/** Enchants the item using the specified number of XP levels.
Returns true if item enchanted, false if not. */
bool EnchantByXPLevels(int a_NumXPLevels); // tolua_export
// tolua_begin
short m_ItemType;

View File

@ -431,7 +431,6 @@ bool cItemHandler::IsTool()
|| (m_ItemType >= 267 && m_ItemType <= 279)
|| (m_ItemType >= 283 && m_ItemType <= 286)
|| (m_ItemType >= 290 && m_ItemType <= 294)
|| (m_ItemType >= 256 && m_ItemType <= 259)
|| (m_ItemType == 325)
|| (m_ItemType == 346);
}

View File

@ -58,13 +58,13 @@ public:
struct FoodInfo
{
int FoodLevel;
double Saturation;
int FoodLevel;
int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
FoodLevel(a_FoodLevel),
Saturation(a_Saturation),
FoodLevel(a_FoodLevel),
PoisonChance(a_PoisonChance)
{
}

View File

@ -34,7 +34,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
void cMobProximityCounter::convertMaps()
{
for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); itr++)
for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); ++itr)
{
m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk)));
}
@ -55,7 +55,7 @@ cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDist
convertMaps();
}
for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); itr++)
for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); ++itr)
{
if (toReturn.m_Begin == m_DistanceToMonster.end())
{

View File

@ -13,7 +13,7 @@ cMobSpawner::cMobSpawner(cMonster::eFamily a_MonsterFamily,const std::set<cMonst
m_NewPack(true),
m_MobType(cMonster::mtInvalidType)
{
for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); itr++)
for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); ++itr)
{
if (cMonster::FamilyFromType(*itr) == a_MonsterFamily)
{
@ -112,7 +112,7 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
for(int i = 0; i < iRandom; i++)
{
itr++;
++itr;
}
return *itr;

View File

@ -36,7 +36,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
{
m_IsSheared = true;
m_World->BroadcastEntityMetadata(*this);
@ -51,9 +52,9 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
}
if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - a_Player.GetEquippedItem().m_ItemDamage))
else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
{
m_WoolColor = 15 - a_Player.GetEquippedItem().m_ItemDamage;
m_WoolColor = 15 - EquippedItem.m_ItemDamage;
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();

View File

@ -37,7 +37,7 @@ public:
void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; }
void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; }
void SetOwner (AString a_NewOwner) { m_OwnerName = a_NewOwner; }
void SetOwner (const AString & a_NewOwner) { m_OwnerName = a_NewOwner; }
void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; }
protected:

View File

@ -17,6 +17,7 @@ struct cMonsterConfig::sAttributesStruct
int m_AttackRange;
double m_AttackRate;
int m_MaxHealth;
bool m_IsFireproof;
};
@ -72,6 +73,7 @@ void cMonsterConfig::Initialize()
Attributes.m_SightDistance = MonstersIniFile.GetValueI(Name, "SightDistance", 0);
Attributes.m_AttackRate = MonstersIniFile.GetValueF(Name, "AttackRate", 0);
Attributes.m_MaxHealth = MonstersIniFile.GetValueI(Name, "MaxHealth", 1);
Attributes.m_IsFireproof = MonstersIniFile.GetValueB(Name, "IsFireproof", false);
m_pState->AttributesList.push_front(Attributes);
} // for i - SplitList[]
}
@ -92,6 +94,7 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na
a_Monster->SetSightDistance(itr->m_SightDistance);
a_Monster->SetAttackRate ((float)itr->m_AttackRate);
a_Monster->SetMaxHealth (itr->m_MaxHealth);
a_Monster->SetIsFireproof (itr->m_IsFireproof);
return;
}
} // for itr - m_pState->AttributesList[]

View File

@ -840,12 +840,14 @@ void cPerlinNoise::Generate2D(
}
// Generate the first octave directly into array:
m_Octaves.front().m_Noise.Generate2D(
const cOctave & FirstOctave = m_Octaves.front();
FirstOctave.m_Noise.Generate2D(
a_Workspace, a_SizeX, a_SizeY,
a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency,
a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency
a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency
);
NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude;
NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
for (int i = 0; i < ArrayCount; i++)
{
a_Array[i] *= Amplitude;
@ -902,13 +904,15 @@ void cPerlinNoise::Generate3D(
}
// Generate the first octave directly into array:
m_Octaves.front().m_Noise.Generate3D(
const cOctave & FirstOctave = m_Octaves.front();
FirstOctave.m_Noise.Generate3D(
a_Workspace, a_SizeX, a_SizeY, a_SizeZ,
a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency,
a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency,
a_StartZ * m_Octaves.front().m_Frequency, a_EndZ * m_Octaves.front().m_Frequency
a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency,
a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency,
a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency
);
NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude;
NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude;
for (int i = 0; i < ArrayCount; i++)
{
a_Array[i] = a_Workspace[i] * Amplitude;

View File

@ -119,9 +119,10 @@ void cAuthenticator::Execute(void)
}
ASSERT(!m_Queue.empty());
int ClientID = m_Queue.front().m_ClientID;
AString UserName = m_Queue.front().m_Name;
AString ServerID = m_Queue.front().m_ServerID;
cAuthenticator::cUser & User = m_Queue.front();
int ClientID = User.m_ClientID;
AString UserName = User.m_Name;
AString ServerID = User.m_ServerID;
m_Queue.pop_front();
Lock.Unlock();

View File

@ -96,6 +96,7 @@ enum
PACKET_INVENTORY_WHOLE = 0x68,
PACKET_WINDOW_PROPERTY = 0x69,
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
PACKET_ENCHANT_ITEM = 0x6C,
PACKET_UPDATE_SIGN = 0x82,
PACKET_ITEM_DATA = 0x83,
PACKET_PLAYER_LIST_ITEM = 0xC9,
@ -537,9 +538,10 @@ void cProtocol125::SendHealth(void)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_HEALTH);
WriteShort((short)m_Client->GetPlayer()->GetHealth());
WriteShort((short)m_Client->GetPlayer()->GetFoodLevel());
WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
cPlayer * Player = m_Client->GetPlayer();
WriteShort((short)Player->GetHealth());
WriteShort((short)Player->GetFoodLevel());
WriteFloat((float)Player->GetFoodSaturationLevel());
Flush();
}
@ -667,13 +669,14 @@ void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PICKUP_SPAWN);
WriteInt (a_Pickup.GetUniqueID());
WriteShort (a_Pickup.GetItem().m_ItemType);
WriteChar (a_Pickup.GetItem().m_ItemCount);
WriteShort (a_Pickup.GetItem().m_ItemDamage);
const cItem & Item = a_Pickup.GetItem();
WriteShort (Item.m_ItemType);
WriteChar (Item.m_ItemCount);
WriteShort (Item.m_ItemDamage);
WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
WriteByte ((char)(a_Pickup.GetSpeed().x * 8));
WriteByte ((char)(a_Pickup.GetSpeed().y * 8));
WriteByte ((char)(a_Pickup.GetSpeed().z * 8));
WriteByte ((char)(a_Pickup.GetSpeedX() * 8));
WriteByte ((char)(a_Pickup.GetSpeedY() * 8));
WriteByte ((char)(a_Pickup.GetSpeedZ() * 8));
Flush();
}
@ -830,10 +833,11 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
void cProtocol125::SendRespawn(void)
{
cCSLock Lock(m_CSPacket);
cPlayer * Player = m_Client->GetPlayer();
WriteByte (PACKET_RESPAWN);
WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension()));
WriteInt ((int)(Player->GetWorld()->GetDimension()));
WriteByte (2); // TODO: Difficulty; 2 = Normal
WriteChar ((char)m_Client->GetPlayer()->GetGameMode());
WriteChar ((char)Player->GetGameMode());
WriteShort (256); // Current world height
WriteString("default");
}
@ -845,10 +849,11 @@ void cProtocol125::SendRespawn(void)
void cProtocol125::SendExperience(void)
{
cCSLock Lock(m_CSPacket);
cPlayer * Player = m_Client->GetPlayer();
WriteByte (PACKET_EXPERIENCE);
WriteFloat (m_Client->GetPlayer()->GetXpPercentage());
WriteShort (m_Client->GetPlayer()->GetXpLevel());
WriteShort (m_Client->GetPlayer()->GetCurrentXp());
WriteFloat (Player->GetXpPercentage());
WriteShort (Player->GetXpLevel());
WriteShort (Player->GetCurrentXp());
Flush();
}
@ -1278,6 +1283,7 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
case PACKET_SLOT_SELECTED: return ParseSlotSelected();
case PACKET_UPDATE_SIGN: return ParseUpdateSign();
case PACKET_USE_ENTITY: return ParseUseEntity();
case PACKET_ENCHANT_ITEM: return ParseEnchantItem();
case PACKET_WINDOW_CLICK: return ParseWindowClick();
case PACKET_WINDOW_CLOSE: return ParseWindowClose();
}
@ -1639,6 +1645,20 @@ int cProtocol125::ParseUseEntity(void)
int cProtocol125::ParseEnchantItem(void)
{
HANDLE_PACKET_READ(ReadByte, Byte, WindowID);
HANDLE_PACKET_READ(ReadByte, Byte, Enchantment);
m_Client->HandleEnchantItem(WindowID, Enchantment);
return PARSE_OK;
}
int cProtocol125::ParseWindowClick(void)
{
HANDLE_PACKET_READ(ReadChar, char, WindowID);

View File

@ -143,6 +143,7 @@ protected:
virtual int ParseSlotSelected (void);
virtual int ParseUpdateSign (void);
virtual int ParseUseEntity (void);
virtual int ParseEnchantItem (void);
virtual int ParseWindowClick (void);
virtual int ParseWindowClose (void);

View File

@ -408,7 +408,8 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window)
super::SendWholeInventory(a_Window);
// Send the player inventory and hotbar:
const cInventory & Inventory = m_Client->GetPlayer()->GetInventory();
cPlayer * Player = m_Client->GetPlayer();
const cInventory & Inventory = Player->GetInventory();
int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots
char WindowID = a_Window.GetWindowID();
for (short i = 0; i < cInventory::invInventoryCount; i++)
@ -422,7 +423,7 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window)
} // for i - Hotbar[]
// Send even the item being dragged:
SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem());
SendInventorySlot(-1, -1, Player->GetDraggingItem());
}
@ -800,10 +801,12 @@ void cProtocol132::SendCompass(const cWorld & a_World)
void cProtocol132::SendEncryptionKeyRequest(void)
{
cCSLock Lock(m_CSPacket);
cServer * Server = cRoot::Get()->GetServer();
WriteByte(0xfd);
WriteString(cRoot::Get()->GetServer()->GetServerID());
WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size()));
SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
WriteString(Server->GetServerID());
const AString & PublicKeyDER = Server->GetPublicKeyDER();
WriteShort((short)(PublicKeyDER.size()));
SendData(PublicKeyDER.data(), PublicKeyDER.size());
WriteShort(4);
WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
Flush();
@ -874,10 +877,11 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
// Prepare the m_AuthServerID:
cSHA1Checksum Checksum;
AString ServerID = cRoot::Get()->GetServer()->GetServerID();
cServer * Server = cRoot::Get()->GetServer();
AString ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);

View File

@ -103,9 +103,9 @@ void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup)
WriteInt (a_Pickup.GetUniqueID());
WriteItem (a_Pickup.GetItem());
WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32));
WriteChar ((char)(a_Pickup.GetSpeed().x * 8));
WriteChar ((char)(a_Pickup.GetSpeed().y * 8));
WriteChar ((char)(a_Pickup.GetSpeed().z * 8));
WriteChar((char)(a_Pickup.GetSpeedX() * 8));
WriteChar((char)(a_Pickup.GetSpeedY() * 8));
WriteChar((char)(a_Pickup.GetSpeedZ() * 8));
Flush();
}
@ -170,9 +170,9 @@ void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup)
WriteInt ((int)(a_Pickup.GetPosY() * 32));
WriteInt ((int)(a_Pickup.GetPosZ() * 32));
WriteInt (1);
WriteShort((short)(a_Pickup.GetSpeed().x * 32));
WriteShort((short)(a_Pickup.GetSpeed().y * 32));
WriteShort((short)(a_Pickup.GetSpeed().z * 32));
WriteShort((short)(a_Pickup.GetSpeedX() * 32));
WriteShort((short)(a_Pickup.GetSpeedY() * 32));
WriteShort((short)(a_Pickup.GetSpeedZ() * 32));
WriteByte(0);
WriteByte(0);

View File

@ -131,9 +131,10 @@ void cProtocol161::SendHealth(void)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_HEALTH);
WriteFloat((float)m_Client->GetPlayer()->GetHealth());
WriteShort((short)m_Client->GetPlayer()->GetFoodLevel());
WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
cPlayer * Player = m_Client->GetPlayer();
WriteFloat((float)Player->GetHealth());
WriteShort((short)Player->GetFoodLevel());
WriteFloat((float)Player->GetFoodSaturationLevel());
Flush();
}
@ -144,11 +145,12 @@ void cProtocol161::SendHealth(void)
void cProtocol161::SendPlayerMaxSpeed(void)
{
cCSLock Lock(m_CSPacket);
cPlayer * Player = m_Client->GetPlayer();
WriteByte(PACKET_ENTITY_PROPERTIES);
WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(Player->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
WriteDouble(0.1 * Player->GetMaxSpeed());
Flush();
}
@ -214,6 +216,25 @@ int cProtocol161::ParseEntityAction(void)
int cProtocol161::ParseLogin(void)
{
// The login packet is sent by Forge clients only
// Only parse the packet, do no extra processing
// Note that the types and the names have been only guessed and are not verified at all!
HANDLE_PACKET_READ(ReadBEInt, int, Int1);
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, String1);
HANDLE_PACKET_READ(ReadChar, char, Char1);
HANDLE_PACKET_READ(ReadChar, char, Char2);
HANDLE_PACKET_READ(ReadChar, char, Char3);
HANDLE_PACKET_READ(ReadByte, Byte, Byte1);
HANDLE_PACKET_READ(ReadByte, Byte, Byte2);
return PARSE_OK;
}
int cProtocol161::ParsePlayerAbilities(void)
{
HANDLE_PACKET_READ(ReadByte, Byte, Flags);
@ -276,11 +297,12 @@ cProtocol162::cProtocol162(cClientHandle * a_Client) :
void cProtocol162::SendPlayerMaxSpeed(void)
{
cCSLock Lock(m_CSPacket);
cPlayer * Player = m_Client->GetPlayer();
WriteByte(PACKET_ENTITY_PROPERTIES);
WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(Player->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
WriteDouble(0.1 * Player->GetMaxSpeed());
WriteShort(0);
Flush();
}

View File

@ -46,6 +46,7 @@ protected:
virtual void SendWindowOpen (const cWindow & a_Window) override;
virtual int ParseEntityAction (void) override;
virtual int ParseLogin (void) override;
virtual int ParsePlayerAbilities(void) override;
// New packets:

View File

@ -563,9 +563,10 @@ void cProtocol172::SendHealth(void)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x06); // Update Health packet
Pkt.WriteFloat((float)m_Client->GetPlayer()->GetHealth());
Pkt.WriteShort(m_Client->GetPlayer()->GetFoodLevel());
Pkt.WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteFloat((float)Player->GetHealth());
Pkt.WriteShort(Player->GetFoodLevel());
Pkt.WriteFloat((float)Player->GetFoodSaturationLevel());
}
@ -607,12 +608,13 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
// Send the Join Game packet:
{
cServer * Server = cRoot::Get()->GetServer();
cPacketizer Pkt(*this, 0x01); // Join Game packet
Pkt.WriteInt(a_Player.GetUniqueID());
Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (cRoot::Get()->GetServer()->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
Pkt.WriteChar((char)a_World.GetDimension());
Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
Pkt.WriteByte(std::min(cRoot::Get()->GetServer()->GetMaxPlayers(), 60));
Pkt.WriteByte(std::min(Server->GetMaxPlayers(), 60));
Pkt.WriteString("default"); // Level type - wtf?
}
@ -758,22 +760,23 @@ void cProtocol172::SendPlayerAbilities(void)
cPacketizer Pkt(*this, 0x39); // Player Abilities packet
Byte Flags = 0;
if (m_Client->GetPlayer()->IsGameModeCreative())
cPlayer * Player = m_Client->GetPlayer();
if (Player->IsGameModeCreative())
{
Flags |= 0x01;
Flags |= 0x08; // Godmode, used for creative
}
if (m_Client->GetPlayer()->IsFlying())
if (Player->IsFlying())
{
Flags |= 0x02;
}
if (m_Client->GetPlayer()->CanFly())
if (Player->CanFly())
{
Flags |= 0x04;
}
Pkt.WriteByte(Flags);
Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed()));
Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed()));
Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed()));
Pkt.WriteFloat((float)(0.1 * Player->GetMaxSpeed()));
}
@ -832,17 +835,18 @@ void cProtocol172::SendPlayerMaxSpeed(void)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x20); // Entity Properties
Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID());
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteInt(Player->GetUniqueID());
Pkt.WriteInt(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed());
if (m_Client->GetPlayer()->IsSprinting())
Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
Pkt.WriteShort(1); // Modifier count
Pkt.WriteInt64(0x662a6b8dda3e4c1c);
Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier
Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed());
Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
Pkt.WriteByte(2);
}
else
@ -860,16 +864,17 @@ void cProtocol172::SendPlayerMoveLook(void)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
Pkt.WriteDouble(m_Client->GetPlayer()->GetPosX());
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteDouble(Player->GetPosX());
// Protocol docs say this is PosY, but #323 says this is eye-pos
// Moreover, the "+ 0.001" is there because otherwise the player falls through the block they were standing on.
Pkt.WriteDouble(m_Client->GetPlayer()->GetStance() + 0.001);
Pkt.WriteDouble(Player->GetStance() + 0.001);
Pkt.WriteDouble(m_Client->GetPlayer()->GetPosZ());
Pkt.WriteFloat((float)m_Client->GetPlayer()->GetYaw());
Pkt.WriteFloat((float)m_Client->GetPlayer()->GetPitch());
Pkt.WriteBool(m_Client->GetPlayer()->IsOnGround());
Pkt.WriteDouble(Player->GetPosZ());
Pkt.WriteFloat((float)Player->GetYaw());
Pkt.WriteFloat((float)Player->GetPitch());
Pkt.WriteBool(Player->IsOnGround());
}
@ -941,9 +946,10 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
void cProtocol172::SendRespawn(void)
{
cPacketizer Pkt(*this, 0x07); // Respawn packet
Pkt.WriteInt(m_Client->GetPlayer()->GetWorld()->GetDimension());
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteInt(Player->GetWorld()->GetDimension());
Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
Pkt.WriteByte((Byte)m_Client->GetPlayer()->GetEffectiveGameMode());
Pkt.WriteByte((Byte)Player->GetEffectiveGameMode());
Pkt.WriteString("default");
}
@ -956,9 +962,10 @@ void cProtocol172::SendExperience (void)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1f); // Experience Packet
Pkt.WriteFloat(m_Client->GetPlayer()->GetXpPercentage());
Pkt.WriteShort(m_Client->GetPlayer()->GetXpLevel());
Pkt.WriteShort(m_Client->GetPlayer()->GetCurrentXp());
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteFloat(Player->GetXpPercentage());
Pkt.WriteShort(Player->GetXpLevel());
Pkt.WriteShort(Player->GetCurrentXp());
}
@ -1580,6 +1587,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
case 0x0f: // Confirm transaction - not used in MCS
case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true;
case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
@ -1634,15 +1642,16 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
{
// Send the response:
AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{";
cServer * Server = cRoot::Get()->GetServer();
AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},",
cRoot::Get()->GetServer()->GetMaxPlayers(),
cRoot::Get()->GetServer()->GetNumPlayers()
Server->GetMaxPlayers(),
Server->GetNumPlayers()
);
AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},",
cRoot::Get()->GetServer()->GetDescription().c_str()
Server->GetDescription().c_str()
);
AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"",
cRoot::Get()->GetServer()->GetFaviconData().c_str()
Server->GetFaviconData().c_str()
);
Response.append("}");
@ -1722,12 +1731,13 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return;
}
cServer * Server = cRoot::Get()->GetServer();
// If auth is required, then send the encryption request:
if (cRoot::Get()->GetServer()->ShouldAuthenticate())
if (Server->ShouldAuthenticate())
{
cPacketizer Pkt(*this, 0x01);
Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID());
const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER();
Pkt.WriteString(Server->GetServerID());
const AString & PubKeyDer = Server->GetPublicKeyDER();
Pkt.WriteShort(PubKeyDer.size());
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
Pkt.WriteShort(4);
@ -2044,6 +2054,18 @@ void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID);
HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment);
m_Client->HandleEnchantItem(WindowID, Enchantment);
}
void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
@ -2268,10 +2290,11 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
// Prepare the m_AuthServerID:
cSHA1Checksum Checksum;
const AString & ServerID = cRoot::Get()->GetServer()->GetServerID();
cServer * Server = cRoot::Get()->GetServer();
const AString & ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
@ -2613,11 +2636,12 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
{
cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
if (!RideableMinecart.GetContent().IsEmpty())
const cItem & MinecartContent = RideableMinecart.GetContent();
if (!MinecartContent.IsEmpty())
{
WriteByte(0x54);
int Content = RideableMinecart.GetContent().m_ItemType;
Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
int Content = MinecartContent.m_ItemType;
Content |= MinecartContent.m_ItemDamage << 8;
WriteInt(Content);
WriteByte(0x55);
WriteInt(RideableMinecart.GetBlockHeight());

View File

@ -280,6 +280,7 @@ protected:
void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer);
void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer);
void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer);
void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer);
void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer);

View File

@ -1003,6 +1003,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
void cProtocolRecognizer::SendLengthlessServerPing(void)
{
AString Reply;
cServer * Server = cRoot::Get()->GetServer();
switch (cRoot::Get()->GetPrimaryServerVersion())
{
case PROTO_VERSION_1_2_5:
@ -1010,11 +1011,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
{
// http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29
Printf(Reply, "%s%s%i%s%i",
cRoot::Get()->GetServer()->GetDescription().c_str(),
Server->GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetNumPlayers(),
Server->GetNumPlayers(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetMaxPlayers()
Server->GetMaxPlayers()
);
break;
}
@ -1044,9 +1045,9 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
// http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100
AString NumPlayers;
Printf(NumPlayers, "%d", cRoot::Get()->GetServer()->GetNumPlayers());
Printf(NumPlayers, "%d", Server->GetNumPlayers());
AString MaxPlayers;
Printf(MaxPlayers, "%d", cRoot::Get()->GetServer()->GetMaxPlayers());
Printf(MaxPlayers, "%d", Server->GetMaxPlayers());
AString ProtocolVersionNum;
Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion());
@ -1060,7 +1061,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
Reply.push_back(0);
Reply.append(ProtocolVersionTxt);
Reply.push_back(0);
Reply.append(cRoot::Get()->GetServer()->GetDescription());
Reply.append(Server->GetDescription());
Reply.push_back(0);
Reply.append(NumPlayers);
Reply.push_back(0);

View File

@ -190,7 +190,7 @@ void cServer::PlayerDestroying(const cPlayer * a_Player)
bool cServer::InitServer(cIniFile & a_SettingsIni)
{
m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!").c_str();
m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!");
m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100);
m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false);
m_PlayerCount = 0;
@ -275,7 +275,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
int cServer::GetNumPlayers(void)
int cServer::GetNumPlayers(void) const
{
cCSLock Lock(m_CSPlayerCount);
return m_PlayerCount;

View File

@ -59,7 +59,7 @@ public: // tolua_export
// Player counts:
int GetMaxPlayers(void) const {return m_MaxPlayers; }
int GetNumPlayers(void);
int GetNumPlayers(void) const;
void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
// Hardcore mode or not:
@ -168,7 +168,7 @@ private:
cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld
cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick()
cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount
mutable cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount
int m_PlayerCount; ///< Number of players currently playing in the server
cCriticalSection m_CSPlayerCountDiff; ///< Locks the m_PlayerCountDiff
int m_PlayerCountDiff; ///< Adjustment to m_PlayerCount to be applied in the Tick thread

View File

@ -350,7 +350,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
{
continue;
}
BlockType = Neighbour->GetBlock(X, a_RelY + gCrossCoords[i].y, Z);
BlockType = Neighbour->GetBlock(X, a_RelY + gNeighborCoords[i].y, Z);
if (!IsFuel(BlockType))
{

View File

@ -155,7 +155,7 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a
Points.push_back(new Vector3i(a_X, a_Y, a_Z + 1));
Points.push_back(new Vector3i(a_X, a_Y, a_Z - 1));
for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); it++)
for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); ++it)
{
Vector3i *Pos = (*it);
char BlockID = m_World.GetBlock(Pos->x, Pos->y, Pos->z);

View File

@ -935,7 +935,8 @@ BOOL StackWalker::LoadModules()
break;
}
} // for (search for path separator...)
if (strlen(szTemp) > 0)
if (szTemp[0] != '\0') // If szTemp is not empty (Note: This is more efficient than using strlen)
{
strcat_s(szSymPath, nSymPathLen, szTemp);
strcat_s(szSymPath, nSymPathLen, ";");

View File

@ -13,6 +13,8 @@
#include "Window.h"
#include "../CraftingRecipes.h"
#include "../Root.h"
#include "../FastRandom.h"
#include "../BlockArea.h"
@ -145,6 +147,7 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
FreeSlots = 0;
}
int Filling = (FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots;
Slot.m_ItemCount += (char)Filling;
DraggingItem.m_ItemCount -= (char)Filling;
if (DraggingItem.m_ItemCount <= 0)
@ -167,7 +170,6 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
{
m_ParentWindow.BroadcastWholeWindow();
}
}
@ -483,6 +485,7 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
// Get the current recipe:
cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
const cItem & Result = Recipe.GetResult();
cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize);
@ -490,16 +493,16 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
// If possible, craft:
if (DraggingItem.IsEmpty())
{
DraggingItem = Recipe.GetResult();
DraggingItem = Result;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
}
else if (DraggingItem.IsEqual(Recipe.GetResult()))
else if (DraggingItem.IsEqual(Result))
{
cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType);
if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize())
cItemHandler * Handler = ItemHandler(Result.m_ItemType);
if (DraggingItem.m_ItemCount + Result.m_ItemCount <= Handler->GetMaxStackSize())
{
DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount;
DraggingItem.m_ItemCount += Result.m_ItemCount;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
}
@ -592,6 +595,307 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnchanting:
cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) :
cSlotAreaTemporary(1, a_ParentWindow)
{
a_ParentWindow.m_SlotArea = this;
}
void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
{
ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
bool bAsync = false;
if (GetSlot(a_SlotNum, a_Player) == NULL)
{
LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum);
return;
}
switch (a_ClickAction)
{
case caShiftLeftClick:
case caShiftRightClick:
{
ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
return;
}
case caDblClick:
{
DblClicked(a_Player, a_SlotNum);
return;
}
default:
{
break;
}
}
cItem Slot(*GetSlot(a_SlotNum, a_Player));
if (!Slot.IsSameType(a_ClickedItem))
{
LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
bAsync = true;
}
cItem & DraggingItem = a_Player.GetDraggingItem();
switch (a_ClickAction)
{
case caRightClick:
{
// Right-clicked
if (DraggingItem.IsEmpty())
{
DraggingItem = Slot.CopyOne();
Slot.Empty();
break;
}
if (Slot.IsEmpty())
{
Slot = DraggingItem.CopyOne();
DraggingItem.m_ItemCount -= 1;
if (DraggingItem.m_ItemCount <= 0)
{
DraggingItem.Empty();
}
}
else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1))
{
// Swap contents
cItem tmp(DraggingItem);
DraggingItem = Slot;
Slot = tmp;
}
break;
}
case caLeftClick:
{
// Left-clicked
if (DraggingItem.IsEmpty())
{
DraggingItem = Slot.CopyOne();
Slot.Empty();
break;
}
if (DraggingItem.IsEqual(Slot))
{
// Do nothing
break;
}
if (!Slot.IsEmpty())
{
if (DraggingItem.m_ItemCount == 1)
{
// Swap contents
cItem tmp(DraggingItem);
DraggingItem = Slot;
Slot = tmp;
}
}
else
{
Slot = DraggingItem.CopyOne();
DraggingItem.m_ItemCount -= 1;
if (DraggingItem.m_ItemCount <= 0)
{
DraggingItem.Empty();
}
}
break;
}
default:
{
LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
m_ParentWindow.BroadcastWholeWindow();
return;
}
} // switch (a_ClickAction
SetSlot(a_SlotNum, a_Player, Slot);
if (bAsync)
{
m_ParentWindow.BroadcastWholeWindow();
}
UpdateResult(a_Player);
}
void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum)
{
cItem & Dragging = a_Player.GetDraggingItem();
if ((!Dragging.IsEmpty()) || (a_SlotNum != 0))
{
return;
}
cItem Item = *GetSlot(0, a_Player);
if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false))
{
m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true);
}
}
void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
{
const cItem * Slot = GetSlot(0, a_Player);
if (!Slot->IsEmpty())
{
return;
}
if (a_Apply)
{
SetSlot(0, a_Player, a_ItemStack.CopyOne());
}
a_ItemStack.m_ItemCount -= 1;
if (a_ItemStack.m_ItemCount <= 0)
{
a_ItemStack.Empty();
}
UpdateResult(a_Player);
}
void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player)
{
// Toss the item in the enchanting slot
TossItems(a_Player, 0, 1);
super::OnPlayerRemoved(a_Player);
}
void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
{
cItem Item = *GetSlot(0, a_Player);
if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty())
{
m_ParentWindow.SetProperty(0, 0, a_Player);
m_ParentWindow.SetProperty(1, 0, a_Player);
m_ParentWindow.SetProperty(2, 0, a_Player);
}
else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK)
{
int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15);
cFastRandom Random;
int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves));
int topSlot = std::max(base / 3, 1);
int middleSlot = (base * 2) / 3 + 1;
int bottomSlot = std::max(base, Bookshelves * 2);
m_ParentWindow.SetProperty(0, topSlot, a_Player);
m_ParentWindow.SetProperty(1, middleSlot, a_Player);
m_ParentWindow.SetProperty(2, bottomSlot, a_Player);
}
else
{
m_ParentWindow.SetProperty(0, 0, a_Player);
m_ParentWindow.SetProperty(1, 0, a_Player);
m_ParentWindow.SetProperty(2, 0, a_Player);
}
}
int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World)
{
int PosX, PosY, PosZ;
((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ);
int Bookshelves = 0;
cBlockArea Area;
Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2);
static const struct
{
int m_BookX, m_BookY, m_BookZ; // Coords to check for bookcases
int m_AirX, m_AirY, m_AirZ; // Coords to check for air; if not air, the bookcase won't be counted
} CheckCoords[] =
{
{ 0, 0, 0, 1, 0, 1 }, // Bookcase at {0, 0, 0}, air at {1, 0, 1}
{ 0, 0, 1, 1, 0, 1 }, // Bookcase at {0, 0, 1}, air at {1, 0, 1}
{ 0, 0, 2, 1, 0, 2 }, // Bookcase at {0, 0, 2}, air at {1, 0, 2}
{ 0, 0, 3, 1, 0, 3 }, // Bookcase at {0, 0, 3}, air at {1, 0, 3}
{ 0, 0, 4, 1, 0, 3 }, // Bookcase at {0, 0, 4}, air at {1, 0, 3}
{ 1, 0, 4, 1, 0, 3 }, // Bookcase at {1, 0, 4}, air at {1, 0, 3}
{ 2, 0, 4, 2, 0, 3 }, // Bookcase at {2, 0, 4}, air at {2, 0, 3}
{ 3, 0, 4, 3, 0, 3 }, // Bookcase at {3, 0, 4}, air at {3, 0, 3}
{ 4, 0, 4, 3, 0, 3 }, // Bookcase at {4, 0, 4}, air at {3, 0, 3}
{ 4, 0, 3, 3, 0, 3 }, // Bookcase at {4, 0, 3}, air at {3, 0, 3}
{ 4, 0, 2, 3, 0, 2 }, // Bookcase at {4, 0, 2}, air at {3, 0, 2}
{ 4, 0, 1, 3, 0, 1 }, // Bookcase at {4, 0, 1}, air at {3, 0, 1}
{ 4, 0, 0, 3, 0, 1 }, // Bookcase at {4, 0, 0}, air at {3, 0, 1}
{ 3, 0, 0, 3, 0, 1 }, // Bookcase at {3, 0, 0}, air at {3, 0, 1}
{ 2, 0, 0, 2, 0, 1 }, // Bookcase at {2, 0, 0}, air at {2, 0, 1}
{ 1, 0, 0, 1, 0, 1 }, // Bookcase at {1, 0, 0}, air at {1, 0, 1}
{ 0, 1, 0, 1, 1, 1 }, // Bookcase at {0, 1, 0}, air at {1, 1, 1}
{ 0, 1, 1, 1, 1, 1 }, // Bookcase at {0, 1, 1}, air at {1, 1, 1}
{ 0, 1, 2, 1, 1, 2 }, // Bookcase at {0, 1, 2}, air at {1, 1, 2}
{ 0, 1, 3, 1, 1, 3 }, // Bookcase at {0, 1, 3}, air at {1, 1, 3}
{ 0, 1, 4, 1, 1, 3 }, // Bookcase at {0, 1, 4}, air at {1, 1, 3}
{ 1, 1, 4, 1, 1, 3 }, // Bookcase at {1, 1, 4}, air at {1, 1, 3}
{ 2, 1, 4, 2, 1, 3 }, // Bookcase at {2, 1, 4}, air at {2, 1, 3}
{ 3, 1, 4, 3, 1, 3 }, // Bookcase at {3, 1, 4}, air at {3, 1, 3}
{ 4, 1, 4, 3, 1, 3 }, // Bookcase at {4, 1, 4}, air at {3, 1, 3}
{ 4, 1, 3, 3, 1, 3 }, // Bookcase at {4, 1, 3}, air at {3, 1, 3}
{ 4, 1, 2, 3, 1, 2 }, // Bookcase at {4, 1, 2}, air at {3, 1, 2}
{ 4, 1, 1, 3, 1, 1 }, // Bookcase at {4, 1, 1}, air at {3, 1, 1}
{ 4, 1, 0, 3, 1, 1 }, // Bookcase at {4, 1, 0}, air at {3, 1, 1}
{ 3, 1, 0, 3, 1, 1 }, // Bookcase at {3, 1, 0}, air at {3, 1, 1}
{ 2, 1, 0, 2, 1, 1 }, // Bookcase at {2, 1, 0}, air at {2, 1, 1}
{ 1, 1, 0, 1, 1, 1 }, // Bookcase at {1, 1, 0}, air at {1, 1, 1}
};
for (size_t i = 0; i < ARRAYCOUNT(CheckCoords); i++)
{
if (
(Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot
(Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place
)
{
Bookshelves++;
}
} // for i - CheckCoords
return Bookshelves;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnderChest:

View File

@ -19,6 +19,8 @@ class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cCraftingRecipe;
class cEnchantingWindow;
class cWorld;
@ -66,7 +68,7 @@ public:
/// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting.
/// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill.
virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks);
protected:
int m_NumSlots;
cWindow & m_ParentWindow;
@ -252,6 +254,34 @@ protected:
class cSlotAreaEnchanting :
public cSlotAreaTemporary
{
typedef cSlotAreaTemporary super;
public:
cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow);
// cSlotArea overrides:
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override;
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
// cSlotAreaTemporary overrides:
virtual void OnPlayerRemoved(cPlayer & a_Player) override;
/* Get the count of bookshelves who stand in the near of the enchanting table */
int GetBookshelvesCount(cWorld * a_World);
protected:
/** Handles a click in the item slot. */
void UpdateResult(cPlayer & a_Player);
};
class cSlotAreaChest :
public cSlotArea
{

View File

@ -804,6 +804,66 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEnchantingWindow:
cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
cWindow(wtEnchantment, "Enchant"),
m_BlockX(a_BlockX),
m_BlockY(a_BlockY),
m_BlockZ(a_BlockZ)
{
m_SlotAreas.push_back(new cSlotAreaEnchanting(*this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
}
void cEnchantingWindow::SetProperty(int a_Property, int a_Value)
{
m_PropertyValue[a_Property] = a_Value;
super::SetProperty(a_Property, a_Value);
}
void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player)
{
m_PropertyValue[a_Property] = a_Value;
super::SetProperty(a_Property, a_Value, a_Player);
}
int cEnchantingWindow::GetPropertyValue(int a_Property)
{
return m_PropertyValue[a_Property];
}
void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
{
a_PosX = m_BlockX;
a_PosY = m_BlockY;
a_PosZ = m_BlockZ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChestWindow:

View File

@ -136,11 +136,11 @@ public:
void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; }
/// Sends the UpdateWindowProperty (0x69) packet to all clients of the window
void SetProperty(int a_Property, int a_Value);
virtual void SetProperty(int a_Property, int a_Value);
/// Sends the UpdateWindowPropert(0x69) packet to the specified player
void SetProperty(int a_Property, int a_Value, cPlayer & a_Player);
virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player);
// tolua_end
void OwnerDestroyed(void);
@ -165,7 +165,7 @@ public:
/// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea
void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum);
protected:
cSlotAreas m_SlotAreas;
@ -231,6 +231,32 @@ public:
class cEnchantingWindow :
public cWindow
{
typedef cWindow super;
public:
cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player) override;
virtual void SetProperty(int a_Property, int a_Value) override;
/** Return the Value of a Property */
int GetPropertyValue(int a_Property);
/** Set the Position Values to the Position of the Enchantment Table */
void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
cSlotArea * m_SlotArea;
protected:
int m_PropertyValue[3];
int m_BlockX, m_BlockY, m_BlockZ;
};
class cFurnaceWindow :
public cWindow
{

View File

@ -229,10 +229,11 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque
} // for itr - Data->m_Form[]
// Parse the URL into individual params:
size_t idxQM = a_Request.GetURL().find('?');
const AString & URL = a_Request.GetURL();
size_t idxQM = URL.find('?');
if (idxQM != AString::npos)
{
cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, a_Request.GetURL().c_str() + idxQM + 1, a_Request.GetURL().length() - idxQM - 1, *Data);
cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, URL.c_str() + idxQM + 1, URL.length() - idxQM - 1, *Data);
URLParams.Finish();
for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr)
{
@ -388,7 +389,6 @@ AString cWebAdmin::GetDefaultPage(void)
{
continue;
}
AString VersionNum;
AppendPrintf(Content, "<li>%s V.%i</li>", itr->second->GetName().c_str(), itr->second->GetVersion());
}
Content += "</ul>";

View File

@ -860,7 +860,7 @@ void cWorld::TickMobs(float a_Dt)
{
m_ChunkMap->SpawnMobs(Spawner);
// do the spawn
for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++)
for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2)
{
SpawnMobFinalize(*itr2);
}
@ -870,14 +870,14 @@ void cWorld::TickMobs(float a_Dt)
// move close mobs
cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(-1, 64 * 16);// MG TODO : deal with this magic number (the 16 is the size of a block)
for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++)
for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; ++itr)
{
itr->second.m_Monster.Tick(a_Dt, itr->second.m_Chunk);
}
// remove too far mobs
cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(128 * 16, -1);// MG TODO : deal with this magic number (the 16 is the size of a block)
for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++)
for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; ++itr)
{
itr->second.m_Monster.Destroy(true);
}
@ -2894,7 +2894,7 @@ void cWorld::TickQueuedBlocks(void)
m_BlockTickQueueCopy.clear();
m_BlockTickQueue.swap(m_BlockTickQueueCopy);
for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); itr++)
for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); ++itr)
{
BlockTickQueueItem * Block = (*itr);
Block->TicksToWait -= 1;
@ -2985,7 +2985,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed)
{
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)

View File

@ -713,7 +713,7 @@ public:
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata
*/
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }

View File

@ -345,7 +345,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) :
void cFastNBTWriter::BeginCompound(const AString & a_Name)
{
if (m_CurrentStack >= MAX_STACK)
if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;
@ -376,7 +376,7 @@ void cFastNBTWriter::EndCompound(void)
void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
{
if (m_CurrentStack >= MAX_STACK)
if (m_CurrentStack >= MAX_STACK - 1)
{
ASSERT(!"Stack overflow");
return;

View File

@ -839,7 +839,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World)
bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World)
{
// Crude data integrity check:
if (a_UncompressedSize < cChunkDef::BlockDataSize)

View File

@ -135,7 +135,7 @@ protected:
bool EraseChunkData(const cChunkCoords & a_Chunk);
/// Loads the chunk from the data (no locking needed)
bool LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World);
bool LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World);
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);