summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg81
-rw-r--r--src/Bindings/LuaWindow.cpp18
-rw-r--r--src/Bindings/LuaWindow.h7
-rw-r--r--src/Bindings/ManualBindings.cpp87
-rw-r--r--src/Bindings/ManualBindings_Network.cpp35
-rw-r--r--src/Bindings/Plugin.h4
-rw-r--r--src/Bindings/PluginLua.cpp91
-rw-r--r--src/Bindings/PluginLua.h87
-rw-r--r--src/Bindings/PluginManager.cpp6
-rw-r--r--src/Bindings/PluginManager.h2
-rw-r--r--src/BlockEntities/BeaconEntity.cpp3
-rw-r--r--src/BlockEntities/BlockEntityWithItems.h2
-rw-r--r--src/BlockEntities/ChestEntity.cpp6
-rw-r--r--src/BlockEntities/DispenserEntity.cpp35
-rw-r--r--src/BlockEntities/DispenserEntity.h5
-rw-r--r--src/BlockEntities/DropSpenserEntity.cpp1
-rw-r--r--src/BlockEntities/EnderChestEntity.cpp2
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp2
-rw-r--r--src/BlockEntities/HopperEntity.cpp1
-rw-r--r--src/BlockEntities/MobSpawnerEntity.cpp2
-rw-r--r--src/BlockID.cpp29
-rw-r--r--src/Blocks/BlockAnvil.h1
-rw-r--r--src/Blocks/BlockBed.cpp24
-rw-r--r--src/Blocks/BlockBed.h25
-rw-r--r--src/Blocks/BlockBigFlower.h2
-rw-r--r--src/Blocks/BlockDirt.h8
-rw-r--r--src/Blocks/BlockEnchantmentTable.h2
-rw-r--r--src/Blocks/BlockFarmland.h2
-rw-r--r--src/Blocks/BlockFluid.h4
-rw-r--r--src/Blocks/BlockPiston.cpp16
-rw-r--r--src/Blocks/BlockPiston.h2
-rw-r--r--src/Blocks/BlockPortal.h2
-rw-r--r--src/Blocks/BlockWorkbench.h2
-rw-r--r--src/Blocks/WorldInterface.h12
-rw-r--r--src/ByteBuffer.cpp174
-rw-r--r--src/ByteBuffer.h43
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/CheckBasicStyle.lua6
-rw-r--r--src/Chunk.cpp32
-rw-r--r--src/Chunk.h6
-rw-r--r--src/ChunkData.cpp2
-rw-r--r--src/ChunkMap.cpp19
-rw-r--r--src/ChunkMap.h67
-rw-r--r--src/ClientHandle.cpp66
-rw-r--r--src/ClientHandle.h26
-rw-r--r--src/Endianness.h30
-rw-r--r--src/Entities/ArrowEntity.cpp13
-rw-r--r--src/Entities/Boat.cpp2
-rw-r--r--src/Entities/Entity.cpp85
-rw-r--r--src/Entities/Entity.h13
-rw-r--r--src/Entities/FallingBlock.cpp5
-rw-r--r--src/Entities/HangingEntity.cpp55
-rw-r--r--src/Entities/HangingEntity.h86
-rw-r--r--src/Entities/ItemFrame.cpp11
-rw-r--r--src/Entities/ItemFrame.h3
-rw-r--r--src/Entities/Minecart.cpp12
-rw-r--r--src/Entities/Painting.cpp18
-rw-r--r--src/Entities/Painting.h18
-rw-r--r--src/Entities/Player.cpp2
-rw-r--r--src/Entities/Player.h14
-rw-r--r--src/Entities/ProjectileEntity.cpp9
-rw-r--r--src/Entities/ProjectileEntity.h12
-rw-r--r--src/FastRandom.cpp34
-rw-r--r--src/FastRandom.h6
-rw-r--r--src/FurnaceRecipe.cpp16
-rw-r--r--src/FurnaceRecipe.h3
-rw-r--r--src/Generating/BioGen.cpp36
-rw-r--r--src/Generating/FinishGen.cpp2
-rw-r--r--src/Generating/IntGen.h68
-rw-r--r--src/Generating/ShapeGen.cpp2
-rw-r--r--src/Globals.h10
-rw-r--r--src/Inventory.h2
-rw-r--r--src/Items/ItemDoor.h2
-rw-r--r--src/Items/ItemPainting.h19
-rw-r--r--src/Items/ItemPotion.h2
-rw-r--r--src/Items/ItemSlab.h4
-rw-r--r--src/Items/ItemSpawnEgg.h2
-rw-r--r--src/Items/ItemThrowable.h4
-rw-r--r--src/LoggerListeners.h1
-rw-r--r--src/Map.cpp4
-rw-r--r--src/Map.h5
-rw-r--r--src/MapManager.cpp2
-rw-r--r--src/MapManager.h11
-rw-r--r--src/MobSpawner.cpp11
-rw-r--r--src/Mobs/AggressiveMonster.cpp5
-rw-r--r--src/Mobs/Blaze.cpp2
-rw-r--r--src/Mobs/Creeper.cpp21
-rw-r--r--src/Mobs/Ghast.cpp2
-rw-r--r--src/Mobs/Monster.cpp2
-rw-r--r--src/Mobs/Sheep.cpp2
-rw-r--r--src/Mobs/Skeleton.cpp3
-rw-r--r--src/OSSupport/CMakeLists.txt1
-rw-r--r--src/OSSupport/CriticalSection.h12
-rw-r--r--src/OSSupport/Network.h3
-rw-r--r--src/OSSupport/NetworkInterfaceEnum.cpp185
-rw-r--r--src/OSSupport/UDPEndpointImpl.cpp9
-rw-r--r--src/OSSupport/UDPEndpointImpl.h2
-rw-r--r--src/Protocol/CMakeLists.txt10
-rw-r--r--src/Protocol/ChunkDataSerializer.cpp20
-rw-r--r--src/Protocol/Packetizer.cpp101
-rw-r--r--src/Protocol/Packetizer.h155
-rw-r--r--src/Protocol/Protocol.h28
-rw-r--r--src/Protocol/Protocol17x.cpp1234
-rw-r--r--src/Protocol/Protocol17x.h114
-rw-r--r--src/Protocol/Protocol18x.cpp1161
-rw-r--r--src/Protocol/Protocol18x.h119
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp38
-rw-r--r--src/Protocol/ProtocolRecognizer.h9
-rw-r--r--src/Root.cpp12
-rw-r--r--src/Root.h4
-rw-r--r--src/Server.cpp2
-rw-r--r--src/Simulator/FireSimulator.cpp2
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp3
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp4
-rw-r--r--src/StringUtils.cpp48
-rw-r--r--src/StringUtils.h5
-rw-r--r--src/UI/AnvilWindow.cpp83
-rw-r--r--src/UI/AnvilWindow.h45
-rw-r--r--src/UI/BeaconWindow.cpp76
-rw-r--r--src/UI/BeaconWindow.h40
-rw-r--r--src/UI/CMakeLists.txt23
-rw-r--r--src/UI/ChestWindow.cpp141
-rw-r--r--src/UI/ChestWindow.h45
-rw-r--r--src/UI/CraftingWindow.cpp61
-rw-r--r--src/UI/CraftingWindow.h31
-rw-r--r--src/UI/DropSpenserWindow.cpp46
-rw-r--r--src/UI/DropSpenserWindow.h32
-rw-r--r--src/UI/EnchantingWindow.cpp100
-rw-r--r--src/UI/EnchantingWindow.h44
-rw-r--r--src/UI/EnderChestWindow.cpp71
-rw-r--r--src/UI/EnderChestWindow.h38
-rw-r--r--src/UI/FurnaceWindow.cpp74
-rw-r--r--src/UI/FurnaceWindow.h32
-rw-r--r--src/UI/HopperWindow.cpp48
-rw-r--r--src/UI/HopperWindow.h32
-rw-r--r--src/UI/InventoryWindow.cpp73
-rw-r--r--src/UI/InventoryWindow.h34
-rw-r--r--src/UI/MinecartWithChestWindow.h67
-rw-r--r--src/UI/SlotArea.cpp130
-rw-r--r--src/UI/SlotArea.h39
-rw-r--r--src/UI/Window.cpp437
-rw-r--r--src/UI/Window.h204
-rw-r--r--src/WebAdmin.h2
-rw-r--r--src/World.cpp156
-rw-r--r--src/World.h102
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp52
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp72
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.h1
-rw-r--r--src/main.cpp220
150 files changed, 4691 insertions, 2967 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 7e174e770..8f55eba07 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -1,4 +1,19 @@
+// AllToLua.pkg
+
+// Defines the bindings that are exported to Lua by the ToLua processor
+
+/*
+ Each file referenced in the $cfile is parsed by ToLua, and bindings are generated for classes and functions
+marked with "// tolua_export", or between the "// tolua_begin" and "// tolua_end" markers.
+
+ Note that if class D inherits from class B, then class B needs to be parsed before class D, otherwise the
+inheritance doesn't work properly (#1789).
+*/
+
+
+
+
$#include "../Globals.h"
// Typedefs from Globals.h, so that we don't have to process that file:
@@ -27,14 +42,38 @@ $cfile "WebPlugin.h"
$cfile "LuaWindow.h"
$cfile "../BlockID.h"
-$cfile "../Mobs/MonsterTypes.h"
$cfile "../BlockInfo.h"
$cfile "../StringUtils.h"
$cfile "../Defines.h"
$cfile "../ChatColor.h"
$cfile "../ClientHandle.h"
-$cfile "../Entities/ArrowEntity.h"
+$cfile "../Server.h"
+$cfile "../World.h"
+$cfile "../Inventory.h"
+$cfile "../Enchantments.h"
+$cfile "../Item.h"
+$cfile "../ItemGrid.h"
+$cfile "../WebAdmin.h"
+$cfile "../Root.h"
+$cfile "../Cuboid.h"
+$cfile "../BoundingBox.h"
+$cfile "../Tracer.h"
+$cfile "../BlockArea.h"
+$cfile "../Generating/ChunkDesc.h"
+$cfile "../CraftingRecipes.h"
+$cfile "../UI/Window.h"
+$cfile "../CompositeChat.h"
+$cfile "../Map.h"
+$cfile "../MapManager.h"
+$cfile "../Scoreboard.h"
+$cfile "../Statistics.h"
+$cfile "../Protocol/MojangAPI.h"
+
+// Entities:
$cfile "../Entities/Entity.h"
+$cfile "../Entities/Pawn.h"
+$cfile "../Entities/ProjectileEntity.h"
+$cfile "../Entities/ArrowEntity.h"
$cfile "../Entities/EntityEffect.h"
$cfile "../Entities/ExpBottleEntity.h"
$cfile "../Entities/FireChargeEntity.h"
@@ -43,25 +82,21 @@ $cfile "../Entities/Floater.h"
$cfile "../Entities/GhastFireballEntity.h"
$cfile "../Entities/HangingEntity.h"
$cfile "../Entities/ItemFrame.h"
-$cfile "../Entities/Pawn.h"
$cfile "../Entities/Player.h"
$cfile "../Entities/Painting.h"
$cfile "../Entities/Pickup.h"
-$cfile "../Entities/ProjectileEntity.h"
$cfile "../Entities/SplashPotionEntity.h"
$cfile "../Entities/ThrownEggEntity.h"
$cfile "../Entities/ThrownEnderPearlEntity.h"
$cfile "../Entities/ThrownSnowballEntity.h"
$cfile "../Entities/TNTEntity.h"
$cfile "../Entities/WitherSkullEntity.h"
-$cfile "../Server.h"
-$cfile "../World.h"
-$cfile "../Inventory.h"
-$cfile "../Enchantments.h"
-$cfile "../Item.h"
-$cfile "../ItemGrid.h"
-$cfile "../BlockEntities/BeaconEntity.h"
+$cfile "../Mobs/MonsterTypes.h"
+$cfile "../Mobs/Monster.h"
+
+// Block entities:
$cfile "../BlockEntities/BlockEntity.h"
+$cfile "../BlockEntities/BeaconEntity.h"
$cfile "../BlockEntities/BlockEntityWithItems.h"
$cfile "../BlockEntities/ChestEntity.h"
$cfile "../BlockEntities/CommandBlockEntity.h"
@@ -76,30 +111,6 @@ $cfile "../BlockEntities/SignEntity.h"
$cfile "../BlockEntities/MobHeadEntity.h"
$cfile "../BlockEntities/MobSpawnerEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h"
-$cfile "../WebAdmin.h"
-$cfile "../Root.h"
-$cfile "../Cuboid.h"
-$cfile "../BoundingBox.h"
-$cfile "../Tracer.h"
-$cfile "../BlockArea.h"
-$cfile "../Generating/ChunkDesc.h"
-$cfile "../CraftingRecipes.h"
-$cfile "../UI/Window.h"
-$cfile "../Mobs/Monster.h"
-$cfile "../CompositeChat.h"
-$cfile "../Map.h"
-$cfile "../MapManager.h"
-$cfile "../Scoreboard.h"
-$cfile "../Statistics.h"
-$cfile "../Protocol/MojangAPI.h"
-
-
-
-
-
-// Need to declare this class so that the usertype is properly registered in Bindings.cpp -
-// it seems impossible to register a usertype in ManualBindings.cpp
-class cLineBlockTracer;
diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp
index 35730878d..d4014059b 100644
--- a/src/Bindings/LuaWindow.cpp
+++ b/src/Bindings/LuaWindow.cpp
@@ -167,6 +167,24 @@ void cLuaWindow::Destroy(void)
+void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer& a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas Areas;
+ for (auto Area : m_SlotAreas)
+ {
+ if (Area != a_ClickedArea)
+ {
+ Areas.push_back(Area);
+ }
+ }
+
+ super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
+}
+
+
+
+
+
void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
if (a_ItemGrid != &m_Contents)
diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h
index dab99a2e2..d4fc58660 100644
--- a/src/Bindings/LuaWindow.h
+++ b/src/Bindings/LuaWindow.h
@@ -35,8 +35,10 @@ This reference needs to be unreferenced in the Destroy() function.
*/
// tolua_begin
class cLuaWindow :
- public cWindow,
- public cItemGrid::cListener
+ public cWindow
+ // tolua_end
+ , public cItemGrid::cListener
+ // tolua_begin
{
typedef cWindow super;
@@ -84,6 +86,7 @@ protected:
// cWindow overrides:
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void Destroy(void) override;
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index cac81f325..6e579b364 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -266,6 +266,24 @@ static int tolua_StringSplit(lua_State * tolua_S)
+static int tolua_StringSplitWithQuotes(lua_State * tolua_S)
+{
+ cLuaState S(tolua_S);
+
+ AString str;
+ AString delim;
+
+ S.GetStackValues(1, str, delim);
+
+ AStringVector Split = StringSplitWithQuotes(str, delim);
+ S.Push(Split);
+ return 1;
+}
+
+
+
+
+
static int tolua_StringSplitAndTrim(lua_State * tolua_S)
{
cLuaState LuaState(tolua_S);
@@ -572,7 +590,7 @@ static int tolua_DoWith(lua_State* tolua_S)
template <
class Ty1,
class Ty2,
- bool (Ty1::*Func1)(int, cItemCallback<Ty2> &)
+ bool (Ty1::*Func1)(UInt32, cItemCallback<Ty2> &)
>
static int tolua_DoWithID(lua_State* tolua_S)
{
@@ -620,11 +638,11 @@ static int tolua_DoWithID(lua_State* tolua_S)
private:
virtual bool Item(Ty2 * a_Item) override
{
- lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call
- tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); // Push the item
+ lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call
+ tolua_pushusertype(LuaState, a_Item, a_Item->GetClass()); // Push the item
if (TableRef != LUA_REFNIL)
{
- lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param
+ lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param
}
int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0);
@@ -1281,23 +1299,27 @@ tolua_lerror:
class cLuaWorldTask :
- public cWorld::cTask
+ public cWorld::cTask,
+ public cPluginLua::cResettable
{
public:
cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) :
- m_Plugin(a_Plugin),
+ cPluginLua::cResettable(a_Plugin),
m_FnRef(a_FnRef)
{
}
protected:
- cPluginLua & m_Plugin;
int m_FnRef;
// cWorld::cTask overrides:
virtual void Run(cWorld & a_World) override
{
- m_Plugin.Call(m_FnRef, &a_World);
+ cCSLock Lock(m_CSPlugin);
+ if (m_Plugin != nullptr)
+ {
+ m_Plugin->Call(m_FnRef, &a_World);
+ }
}
} ;
@@ -1336,7 +1358,9 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
}
- self->QueueTask(make_unique<cLuaWorldTask>(*Plugin, FnRef));
+ auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef);
+ Plugin->AddResettable(task);
+ self->QueueTask(task);
return 0;
}
@@ -1345,23 +1369,27 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
class cLuaScheduledWorldTask :
- public cWorld::cTask
+ public cWorld::cTask,
+ public cPluginLua::cResettable
{
public:
cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) :
- m_Plugin(a_Plugin),
+ cPluginLua::cResettable(a_Plugin),
m_FnRef(a_FnRef)
{
}
protected:
- cPluginLua & m_Plugin;
int m_FnRef;
// cWorld::cTask overrides:
virtual void Run(cWorld & a_World) override
{
- m_Plugin.Call(m_FnRef, &a_World);
+ cCSLock Lock(m_CSPlugin);
+ if (m_Plugin != nullptr)
+ {
+ m_Plugin->Call(m_FnRef, &a_World);
+ }
}
};
@@ -1407,7 +1435,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0);
- World->ScheduleTask(DelayTicks, new cLuaScheduledWorldTask(*Plugin, FnRef));
+ auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef);
+ Plugin->AddResettable(task);
+ World->ScheduleTask(DelayTicks, task);
return 0;
}
@@ -3659,19 +3689,22 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr);
tolua_usertype(tolua_S, "cStringCompression");
tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr);
+ tolua_usertype(tolua_S, "cLineBlockTracer");
+ tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr);
// Globals:
- tolua_function(tolua_S, "Clamp", tolua_Clamp);
- tolua_function(tolua_S, "StringSplit", tolua_StringSplit);
- tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim);
- tolua_function(tolua_S, "LOG", tolua_LOG);
- tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO);
- tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN);
- tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN);
- tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR);
- tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode);
- tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode);
- tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead
+ tolua_function(tolua_S, "Clamp", tolua_Clamp);
+ tolua_function(tolua_S, "StringSplit", tolua_StringSplit);
+ tolua_function(tolua_S, "StringSplitWithQuotes", tolua_StringSplitWithQuotes);
+ tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim);
+ tolua_function(tolua_S, "LOG", tolua_LOG);
+ tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO);
+ tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN);
+ tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN);
+ tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR);
+ tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode);
+ tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode);
+ tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead
tolua_beginmodule(tolua_S, "cFile");
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);
@@ -3846,6 +3879,10 @@ void ManualBindings::Bind(lua_State * tolua_S)
BindRankManager(tolua_S);
BindNetwork(tolua_S);
+ tolua_beginmodule(tolua_S, "cEntity");
+ tolua_constant(tolua_S, "INVALID_ID", cEntity::INVALID_ID);
+ tolua_endmodule(tolua_S);
+
tolua_endmodule(tolua_S);
}
diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp
index a628eb9ca..628cda7f0 100644
--- a/src/Bindings/ManualBindings_Network.cpp
+++ b/src/Bindings/ManualBindings_Network.cpp
@@ -129,6 +129,30 @@ static int tolua_cNetwork_CreateUDPEndpoint(lua_State * L)
+/** Binds cNetwork::EnumLocalIPAddresses */
+static int tolua_cNetwork_EnumLocalIPAddresses(lua_State * L)
+{
+ // Function signature:
+ // cNetwork:EnumLocalIPAddresses() -> {string, ...}
+
+ cLuaState S(L);
+ if (
+ !S.CheckParamUserTable(1, "cNetwork") ||
+ !S.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ // Push the enumerated addresses:
+ S.Push(cNetwork::EnumLocalIPAddresses());
+ return 1;
+}
+
+
+
+
+
/** Binds cNetwork::HostnameToIP */
static int tolua_cNetwork_HostnameToIP(lua_State * L)
{
@@ -903,11 +927,12 @@ void ManualBindings::BindNetwork(lua_State * tolua_S)
// Fill in the functions (alpha-sorted):
tolua_beginmodule(tolua_S, "cNetwork");
- tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect);
- tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint);
- tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP);
- tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname);
- tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen);
+ tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect);
+ tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint);
+ tolua_function(tolua_S, "EnumLocalIPAddresses", tolua_cNetwork_EnumLocalIPAddresses);
+ tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP);
+ tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname);
+ tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cServerHandle");
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 6ade8ef9f..3f9fa7655 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -111,12 +111,12 @@ public:
Command permissions have already been checked.
Returns true if command handled successfully
*/
- virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) = 0;
+ virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) = 0;
/** Handles the console command split into a_Split.
Returns true if command handled successfully. Output is to be sent to the a_Output callback.
*/
- virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) = 0;
+ virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) = 0;
/// All bound commands are to be removed, do any language-dependent cleanup here
virtual void ClearCommands(void) {}
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index fb7650d42..0a2a8411d 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -6,10 +6,11 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#ifdef __APPLE__
-#define LUA_USE_MACOSX
+ #define LUA_USE_MACOSX
#else
-#define LUA_USE_POSIX
+ #define LUA_USE_POSIX
#endif
+
#include "PluginLua.h"
#include "../CommandOutput.h"
#include "PluginManager.h"
@@ -52,24 +53,40 @@ cPluginLua::~cPluginLua()
void cPluginLua::Close(void)
{
- if (m_LuaState.IsValid())
- {
- // Release all the references in the hook map:
- for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
- {
- for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
- {
- delete *itrR;
- } // for itrR - itrH->second[]
- } // for itrH - m_HookMap[]
- m_HookMap.clear();
-
- m_LuaState.Close();
- }
- else
+ cCSLock Lock(m_CriticalSection);
+
+ // If already closed, bail out:
+ if (!m_LuaState.IsValid())
{
+ ASSERT(m_Resettables.empty());
ASSERT(m_HookMap.empty());
+ return;
}
+
+ // Notify and remove all m_Resettables (unlock the m_CriticalSection while resetting them):
+ cResettablePtrs resettables;
+ std::swap(m_Resettables, resettables);
+ {
+ cCSUnlock Unlock(Lock);
+ for (auto resettable: resettables)
+ {
+ resettable->Reset();
+ }
+ m_Resettables.clear();
+ } // cCSUnlock (m_CriticalSection)
+
+ // Release all the references in the hook map:
+ for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
+ {
+ for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
+ {
+ delete *itrR;
+ } // for itrR - itrH->second[]
+ } // for itrH - m_HookMap[]
+ m_HookMap.clear();
+
+ // Close the Lua engine:
+ m_LuaState.Close();
}
@@ -1465,7 +1482,7 @@ bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, s
-bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player)
+bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand)
{
ASSERT(!a_Split.empty());
CommandMap::iterator cmd = m_Commands.find(a_Split[0]);
@@ -1477,7 +1494,7 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(cmd->second, a_Split, &a_Player, cLuaState::Return, res);
+ m_LuaState.Call(cmd->second, a_Split, &a_Player, a_FullCommand, cLuaState::Return, res);
return res;
}
@@ -1485,7 +1502,7 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player
-bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output)
+bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand)
{
ASSERT(!a_Split.empty());
CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]);
@@ -1500,7 +1517,7 @@ bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOut
cCSLock Lock(m_CriticalSection);
bool res = false;
AString str;
- m_LuaState.Call(cmd->second, a_Split, cLuaState::Return, res, str);
+ m_LuaState.Call(cmd->second, a_Split, a_FullCommand, cLuaState::Return, res, str);
if (res && !str.empty())
{
a_Output.Out(str);
@@ -1709,6 +1726,16 @@ int cPluginLua::CallFunctionFromForeignState(
+void cPluginLua::AddResettable(cPluginLua::cResettablePtr a_Resettable)
+{
+ cCSLock Lock(m_CriticalSection);
+ m_Resettables.push_back(a_Resettable);
+}
+
+
+
+
+
AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request)
{
cCSLock Lock(m_CriticalSection);
@@ -1826,3 +1853,25 @@ void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int
+
+////////////////////////////////////////////////////////////////////////////////
+// cPluginLua::cResettable:
+
+cPluginLua::cResettable::cResettable(cPluginLua & a_Plugin):
+ m_Plugin(&a_Plugin)
+{
+}
+
+
+
+
+
+void cPluginLua::cResettable::Reset(void)
+{
+ cCSLock Lock(m_CSPlugin);
+ m_Plugin = nullptr;
+}
+
+
+
+
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index 7b528501b..c14b02687 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -59,6 +59,37 @@ public:
/** RAII lock for m_Plugin.m_CriticalSection */
cCSLock m_Lock;
} ;
+
+
+
+ /** A base class that represents something related to a plugin
+ The plugin can reset this class so that the instance can continue to exist but will not engage the (possibly non-existent) plugin anymore.
+ This is used for scheduled tasks etc., so that they can be queued and reset when the plugin is terminated, without removing them from the queue. */
+ class cResettable
+ {
+ public:
+ /** Creates a new instance bound to the specified plugin. */
+ cResettable(cPluginLua & a_Plugin);
+
+ // Force a virtual destructor in descendants:
+ virtual ~cResettable() {}
+
+ /** Resets the plugin instance stored within.
+ The instance will continue to exist, but should not call into the plugin anymore. */
+ virtual void Reset(void);
+
+ protected:
+ /** The plugin that this instance references.
+ If nullptr, the plugin has already unloaded and the instance should bail out any processing.
+ Protected against multithreaded access by m_CSPlugin. */
+ cPluginLua * m_Plugin;
+
+ /** The mutex protecting m_Plugin against multithreaded access. */
+ cCriticalSection m_CSPlugin;
+ };
+
+ typedef SharedPtr<cResettable> cResettablePtr;
+ typedef std::vector<cResettablePtr> cResettablePtrs;
cPluginLua(const AString & a_PluginDirectory);
@@ -131,9 +162,9 @@ public:
virtual bool OnWorldStarted (cWorld & a_World) override;
virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) override;
- virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) override;
+ virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) override;
- virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) override;
+ virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) override;
virtual void ClearCommands(void) override;
@@ -187,42 +218,16 @@ public:
int a_ParamEnd
);
- // The following templates allow calls to arbitrary Lua functions residing in the plugin:
-
- /** Call a Lua function with 0 args */
- template <typename FnT> bool Call(FnT a_Fn)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn);
- }
-
- /** Call a Lua function with 1 arg */
- template <typename FnT, typename ArgT0> bool Call(FnT a_Fn, ArgT0 a_Arg0)
+ /** Call a Lua function residing in the plugin. */
+ template <typename FnT, typename... Args>
+ bool Call(FnT a_Fn, Args && ... a_Args)
{
cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0);
+ return m_LuaState.Call(a_Fn, a_Args...);
}
- /** Call a Lua function with 2 args */
- template <typename FnT, typename ArgT0, typename ArgT1> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1);
- }
-
- /** Call a Lua function with 3 args */
- template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2);
- }
-
- /** Call a Lua function with 4 args */
- template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2, typename ArgT3> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2, a_Arg3);
- }
+ /** Adds the specified cResettable instance to m_Resettables, so that it is notified when the plugin is being closed. */
+ void AddResettable(cResettablePtr a_Resettable);
protected:
/** Maps command name into Lua function reference */
@@ -234,15 +239,27 @@ protected:
/** Maps hook types into arrays of Lua function references to call for each hook type */
typedef std::map<int, cLuaRefs> cHookMap;
+
+ /** The mutex protecting m_LuaState and each of the m_Resettables[] against multithreaded use. */
cCriticalSection m_CriticalSection;
+
+ /** The plugin's Lua state. */
cLuaState m_LuaState;
+ /** Objects that need notification when the plugin is about to be unloaded. */
+ cResettablePtrs m_Resettables;
+
+ /** In-game commands that the plugin has registered. */
CommandMap m_Commands;
+
+ /** Console commands that the plugin has registered. */
CommandMap m_ConsoleCommands;
+ /** Hooks that the plugin has registered. */
cHookMap m_HookMap;
- /** Releases all Lua references and closes the LuaState */
+
+ /** Releases all Lua references, notifies and removes all m_Resettables[] and closes the m_LuaState. */
void Close(void);
} ; // tolua_export
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 41b36337e..8935f7dd3 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1465,7 +1465,7 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player,
ASSERT(cmd->second.m_Plugin != nullptr);
- if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player))
+ if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player, a_Command))
{
return crError;
}
@@ -1768,7 +1768,7 @@ bool cPluginManager::IsConsoleCommandBound(const AString & a_Command)
-bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output)
+bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command)
{
if (a_Split.empty())
{
@@ -1795,7 +1795,7 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma
return false;
}
- return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output);
+ return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output, a_Command);
}
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index c8b4de9d6..4efcbb6f3 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -284,7 +284,7 @@ public:
bool IsConsoleCommandBound(const AString & a_Command); // tolua_export
/** Executes the command split into a_Split, as if it was given on the console. Returns true if executed. Output is sent to the a_Output callback */
- bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
+ bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command);
/** Appends all commands beginning with a_Text (case-insensitive) into a_Results.
If a_Player is not nullptr, only commands for which the player has permissions are added.
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp
index 37ce7a8ab..fb3940ce9 100644
--- a/src/BlockEntities/BeaconEntity.cpp
+++ b/src/BlockEntities/BeaconEntity.cpp
@@ -4,6 +4,7 @@
#include "BeaconEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
+#include "../UI/BeaconWindow.h"
@@ -289,7 +290,7 @@ void cBeaconEntity::UsedBy(cPlayer * a_Player)
OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
-
+
if (Window != nullptr)
{
// if (a_Player->GetWindow() != Window)
diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h
index 2c2ced1cb..740dbca51 100644
--- a/src/BlockEntities/BlockEntityWithItems.h
+++ b/src/BlockEntities/BlockEntityWithItems.h
@@ -21,7 +21,9 @@
// tolua_begin
class cBlockEntityWithItems :
public cBlockEntity,
+ // tolua_end
public cItemGrid::cListener,
+ // tolua_begin
public cBlockEntityWindowOwner
{
typedef cBlockEntity super;
diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp
index 0cd9c66e0..1c186310c 100644
--- a/src/BlockEntities/ChestEntity.cpp
+++ b/src/BlockEntities/ChestEntity.cpp
@@ -4,7 +4,7 @@
#include "ChestEntity.h"
#include "../Item.h"
#include "../Entities/Player.h"
-#include "../UI/Window.h"
+#include "../UI/ChestWindow.h"
@@ -80,7 +80,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
void cChestEntity::OpenNewWindow(void)
{
// TODO: cats are an obstruction
- if ((GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())))
+ if ((GetPosY() < cChunkDef::Height - 1) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())))
{
// Obstruction, don't open
return;
@@ -99,7 +99,7 @@ void cChestEntity::OpenNewWindow(void)
virtual bool Item(cChestEntity * a_Chest) override
{
- if ((a_Chest->GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ())))
+ if ((a_Chest->GetPosY() < cChunkDef::Height - 1) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ())))
{
// Obstruction, don't open
return false;
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index 42a0476b6..a847f1b65 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -105,7 +105,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- if (m_World->SpawnMob(MobX, DispY, MobZ, static_cast<eMonsterType>(m_Contents.GetSlot(a_SlotNum).m_ItemDamage)) >= 0)
+ if (m_World->SpawnMob(MobX, DispY, MobZ, static_cast<eMonsterType>(m_Contents.GetSlot(a_SlotNum).m_ItemDamage)) != cEntity::INVALID_ID)
{
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
@@ -144,29 +144,37 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
case E_ITEM_FIRE_CHARGE:
{
- SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20);
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
break;
}
case E_ITEM_ARROW:
{
- SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
break;
}
case E_ITEM_SNOWBALL:
{
- SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
break;
}
case E_ITEM_EGG:
{
- SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
break;
}
@@ -188,9 +196,14 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
-void cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector)
+UInt32 cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector)
{
- m_World->CreateProjectile(static_cast<double>(a_BlockX + 0.5), static_cast<double>(a_BlockY + 0.5), static_cast<double>(a_BlockZ + 0.5), a_Kind, nullptr, nullptr, &a_ShootVector);
+ return m_World->CreateProjectile(
+ static_cast<double>(a_BlockX + 0.5),
+ static_cast<double>(a_BlockY + 0.5),
+ static_cast<double>(a_BlockZ + 0.5),
+ a_Kind, nullptr, nullptr, &a_ShootVector
+ );
}
diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h
index 12e12942a..62072d43b 100644
--- a/src/BlockEntities/DispenserEntity.h
+++ b/src/BlockEntities/DispenserEntity.h
@@ -24,8 +24,9 @@ public:
// tolua_begin
- /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. */
- void SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed);
+ /** Spawns a projectile of the given kind in front of the dispenser with the specified speed.
+ Returns the UniqueID of the spawned projectile, or 0 on failure. */
+ UInt32 SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed);
/** Returns a unit vector in the cardinal direction of where the dispenser is facing. */
Vector3d GetShootVector(NIBBLETYPE a_Meta);
diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp
index 5e98506f1..039f5d360 100644
--- a/src/BlockEntities/DropSpenserEntity.cpp
+++ b/src/BlockEntities/DropSpenserEntity.cpp
@@ -8,6 +8,7 @@
#include "DropSpenserEntity.h"
#include "../Entities/Player.h"
#include "../Chunk.h"
+#include "../UI/DropSpenserWindow.h"
diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp
index e18490a1e..ab5c5a2de 100644
--- a/src/BlockEntities/EnderChestEntity.cpp
+++ b/src/BlockEntities/EnderChestEntity.cpp
@@ -4,7 +4,7 @@
#include "EnderChestEntity.h"
#include "../Item.h"
#include "../Entities/Player.h"
-#include "../UI/Window.h"
+#include "../UI/EnderChestWindow.h"
diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index cc5a00af7..2621b560b 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "FurnaceEntity.h"
-#include "../UI/Window.h"
+#include "../UI/FurnaceWindow.h"
#include "../Entities/Player.h"
#include "../Root.h"
#include "../Chunk.h"
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index c2d6cabbb..bfd4b8322 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -9,6 +9,7 @@
#include "../Entities/Player.h"
#include "../Entities/Pickup.h"
#include "../Bindings/PluginManager.h"
+#include "../UI/HopperWindow.h"
#include "ChestEntity.h"
#include "FurnaceEntity.h"
diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp
index 9b3f605f9..764d7af84 100644
--- a/src/BlockEntities/MobSpawnerEntity.cpp
+++ b/src/BlockEntities/MobSpawnerEntity.cpp
@@ -169,7 +169,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
Monster->SetPosition(PosX, RelY, PosZ);
Monster->SetYaw(Random.NextFloat() * 360.0f);
- if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != mtInvalidType)
+ if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID)
{
EntitiesSpawned = true;
Chunk->BroadcastSoundParticleEffect(2004, (int)(PosX * 8.0), (int)(RelY * 8.0), (int)(PosZ * 8.0), 0);
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 06f4232d3..7f0db3cfc 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -26,8 +26,18 @@ class cBlockIDMap
typedef std::map<AString, std::pair<short, short>, Comparator> ItemMap;
public:
+ static bool m_bHasRunInit;
+
cBlockIDMap(void)
{
+ // Dont load items.ini on construct, this will search the wrong path when running as a service.
+ }
+
+
+ void init()
+ {
+ m_bHasRunInit = true;
+
cIniFile Ini;
if (!Ini.ReadFile("items.ini"))
{
@@ -174,7 +184,7 @@ protected:
-
+bool cBlockIDMap::m_bHasRunInit = false;
static cBlockIDMap gsBlockIDMap;
@@ -209,6 +219,10 @@ int BlockStringToType(const AString & a_BlockTypeString)
return res;
}
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString));
}
@@ -222,6 +236,11 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
{
ItemName = ItemName.substr(10);
}
+
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.ResolveItem(ItemName, a_Item);
}
@@ -231,6 +250,10 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
AString ItemToString(const cItem & a_Item)
{
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Desolve(a_Item.m_ItemType, a_Item.m_ItemDamage);
}
@@ -240,6 +263,10 @@ AString ItemToString(const cItem & a_Item)
AString ItemTypeToString(short a_ItemType)
{
+ if (!gsBlockIDMap.m_bHasRunInit)
+ {
+ gsBlockIDMap.init();
+ }
return gsBlockIDMap.Desolve(a_ItemType, -1);
}
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
index 20514580e..abfa0f782 100644
--- a/src/Blocks/BlockAnvil.h
+++ b/src/Blocks/BlockAnvil.h
@@ -4,6 +4,7 @@
#include "BlockHandler.h"
#include "../World.h"
#include "../Entities/Player.h"
+#include "../UI/AnvilWindow.h"
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index 57b9855d0..e56f4bfe0 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -1,14 +1,9 @@
#include "Globals.h"
#include "BlockBed.h"
-
-
-
#include "BroadcastInterface.h"
-#include "ChunkInterface.h"
#include "Entities/../World.h"
#include "Entities/Player.h"
-#include "WorldInterface.h"
@@ -64,21 +59,22 @@ class cPlayerBedStateUnsetter :
public cPlayerListCallback
{
public:
- cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
- m_Position(a_Position), m_WorldInterface(a_WorldInterface)
+ cPlayerBedStateUnsetter(Vector3i a_Position, cChunkInterface & a_ChunkInterface) :
+ m_Position(a_Position),
+ m_ChunkInterface(a_ChunkInterface)
{
}
virtual bool Item(cPlayer * a_Player) override
{
+ cBlockBedHandler::SetBedOccupationState(m_ChunkInterface, a_Player->GetLastBedPos(), false);
a_Player->SetIsInBed(false);
- m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
return false;
}
private:
Vector3i m_Position;
- cWorldInterface & m_WorldInterface;
+ cChunkInterface & m_ChunkInterface;
};
@@ -97,7 +93,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
if (a_WorldInterface.GetTimeOfDay() > 13000)
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- if (Meta & 0x4)
+ if ((Meta & 0x4) == 0x4)
{
a_Player->SendMessageFailure("This bed is occupied");
}
@@ -105,7 +101,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
{
Vector3i PillowDirection(0, 0, 0);
- if (Meta & 0x8)
+ if ((Meta & 0x8) == 0x8)
{
// Is pillow
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX, a_BlockY, a_BlockZ);
@@ -122,15 +118,15 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
}
- a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
- a_Player->SetIsInBed(true);
a_Player->SetBedPos(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
+ SetBedOccupationState(a_ChunkInterface, a_Player->GetLastBedPos(), true);
+ a_Player->SetIsInBed(true);
a_Player->SendMessageSuccess("Home position set successfully");
cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
{
- cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
+ cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_ChunkInterface);
a_WorldInterface.ForEachPlayer(Unsetter);
a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index 5b746110a..46f361686 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -4,9 +4,9 @@
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Item.h"
+#include "ChunkInterface.h"
-class cChunkInterface;
class cPlayer;
class cWorldInterface;
@@ -21,17 +21,14 @@ public:
: cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
-
-
+
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
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;
-
virtual bool IsUseable(void) override
{
return true;
}
-
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
@@ -39,14 +36,12 @@ public:
a_Pickups.push_back(cItem(E_ITEM_BED, 1, 0));
}
-
virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override
{
return true;
}
-
// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
@@ -61,7 +56,6 @@ public:
return ((char)a_Rotation + 2) % 4;
}
-
static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
@@ -73,6 +67,21 @@ public:
}
return Vector3i();
}
+
+ static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied)
+ {
+ auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z);
+ if (a_IsOccupied)
+ {
+ Meta |= 0x04; // Where 0x4 = occupied bit
+ }
+ else
+ {
+ Meta &= 0x0b; // Clear the "occupied" bit of the bed's block
+ }
+
+ a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta);
+ }
} ;
diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h
index 5240ddf53..6c5cc6b68 100644
--- a/src/Blocks/BlockBigFlower.h
+++ b/src/Blocks/BlockBigFlower.h
@@ -81,7 +81,7 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
- return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER)));
+ return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height - 1) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER)));
}
diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h
index 12bca92dd..32512a2ef 100644
--- a/src/Blocks/BlockDirt.h
+++ b/src/Blocks/BlockDirt.h
@@ -59,7 +59,7 @@ public:
a_Chunk.GetWorld()->QueueLightChunk(a_Chunk.GetPosX(), a_Chunk.GetPosZ());
return;
}
- else if (std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY + 1, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY + 1, a_RelZ))) < 9)
+ else if ((a_RelY < cChunkDef::Height - 1) && std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY + 1, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY + 1, a_RelZ))) < 9)
{
// Source block is not bright enough to spread
return;
@@ -69,9 +69,9 @@ public:
cFastRandom rand;
for (int i = 0; i < 2; i++) // Pick two blocks to grow to
{
- int OfsX = rand.NextInt(3, a_RelX) - 1; // [-1 .. 1]
- int OfsY = rand.NextInt(5, a_RelY) - 3; // [-3 .. 1]
- int OfsZ = rand.NextInt(3, a_RelZ) - 1; // [-1 .. 1]
+ int OfsX = rand.NextInt(3) - 1; // [-1 .. 1]
+ int OfsY = rand.NextInt(5) - 3; // [-3 .. 1]
+ int OfsZ = rand.NextInt(3) - 1; // [-1 .. 1]
BLOCKTYPE DestBlock;
NIBBLETYPE DestMeta;
diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h
index 81d2cb9a0..40001f356 100644
--- a/src/Blocks/BlockEnchantmentTable.h
+++ b/src/Blocks/BlockEnchantmentTable.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../UI/Window.h"
+#include "../UI/EnchantingWindow.h"
#include "../Entities/Player.h"
diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h
index 02a48a4af..23a7392da 100644
--- a/src/Blocks/BlockFarmland.h
+++ b/src/Blocks/BlockFarmland.h
@@ -45,7 +45,7 @@ public:
}
// Farmland too dry. If nothing is growing on top, turn back to dirt:
- BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
+ BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height - 1) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
switch (UpperBlock)
{
case E_BLOCK_CROPS:
diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h
index 8c0aae041..2823baedc 100644
--- a/src/Blocks/BlockFluid.h
+++ b/src/Blocks/BlockFluid.h
@@ -99,7 +99,7 @@ public:
// Check if it's fuel:
BLOCKTYPE BlockType;
if (
- ((a_RelY + y < 0) || (a_RelY + y > cChunkDef::Height)) ||
+ ((a_RelY + y < 0) || (a_RelY + y >= cChunkDef::Height)) ||
!a_Chunk.UnboundedRelGetBlockType(a_RelX + x, a_RelY + y, a_RelZ + z, BlockType) ||
!cFireSimulator::IsFuel(BlockType)
)
@@ -126,7 +126,7 @@ public:
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
{
if (
- ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y <= cChunkDef::Height)) &&
+ ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y < cChunkDef::Height)) &&
a_Chunk.UnboundedRelGetBlockType(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, BlockType) &&
(BlockType == E_BLOCK_AIR)
)
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 8d245cabe..d9f4913d8 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -61,6 +61,16 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
+void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
+{
+ // Returning Piston Item without Direction-Metavalue
+ a_Pickups.push_back(cItem(m_BlockType, 1));
+}
+
+
+
+
+
bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@@ -169,7 +179,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ,
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8);
a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false);
- a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
}
@@ -219,7 +229,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
std::vector<Vector3i> ScheduledBlocks;
ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz));
- a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
return;
}
}
@@ -229,7 +239,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
std::vector<Vector3i> ScheduledBlocks;
ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
- a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
}
diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h
index f868f4d8e..9a891025a 100644
--- a/src/Blocks/BlockPiston.h
+++ b/src/Blocks/BlockPiston.h
@@ -15,6 +15,8 @@ public:
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override;
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h
index 97ba26ee3..581a29447 100644
--- a/src/Blocks/BlockPortal.h
+++ b/src/Blocks/BlockPortal.h
@@ -55,7 +55,7 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
- if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height))
+ if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height - 1))
{
return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1
}
diff --git a/src/Blocks/BlockWorkbench.h b/src/Blocks/BlockWorkbench.h
index 699badaf2..e40e15606 100644
--- a/src/Blocks/BlockWorkbench.h
+++ b/src/Blocks/BlockWorkbench.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../UI/Window.h"
+#include "../UI/CraftingWindow.h"
#include "../Entities/Player.h"
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index 106c314e7..44c118195 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -30,14 +30,16 @@ public:
/** Spawns item pickups for each item in the list. May compress pickups if too many entities: */
virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) = 0;
- /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */
+ /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified. */
virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) = 0;
- /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
- virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0;
+ /** Spawns a mob of the specified type.
+ Returns the mob's UniqueID if recognized and spawned, or cEntity::INVALID_ID on failure. */
+ virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0;
- /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
- virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
+ /** Spawns an experience orb at the given location with the given reward.
+ Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */
+ virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 0;
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index f3dc44d91..dc757d8f6 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -81,9 +81,9 @@ public:
void TestWrite(void)
{
cByteBuffer buf(50);
- buf.WriteVarInt(5);
- buf.WriteVarInt(300);
- buf.WriteVarInt(0);
+ buf.WriteVarInt32(5);
+ buf.WriteVarInt32(300);
+ buf.WriteVarInt32(0);
AString All;
buf.ReadAll(All);
assert_test(All.size() == 4);
@@ -101,8 +101,8 @@ public:
assert_test(buf.Write("a", 1));
assert_test(buf.CanReadBytes(1));
assert_test(buf.GetReadableSpace() == 1);
- unsigned char v = 0;
- assert_test(buf.ReadByte(v));
+ UInt8 v = 0;
+ assert_test(buf.ReadBEUInt8(v));
assert_test(v == 'a');
assert_test(buf.GetReadableSpace() == 0);
buf.CommitRead();
@@ -317,7 +317,7 @@ bool cByteBuffer::CanWriteBytes(size_t a_Count) const
-bool cByteBuffer::ReadChar(char & a_Value)
+bool cByteBuffer::ReadBEInt8(Int8 & a_Value)
{
CHECK_THREAD
CheckValid();
@@ -330,7 +330,7 @@ bool cByteBuffer::ReadChar(char & a_Value)
-bool cByteBuffer::ReadByte(unsigned char & a_Value)
+bool cByteBuffer::ReadBEUInt8(UInt8 & a_Value)
{
CHECK_THREAD
CheckValid();
@@ -343,15 +343,15 @@ bool cByteBuffer::ReadByte(unsigned char & a_Value)
-bool cByteBuffer::ReadBEShort(short & a_Value)
+bool cByteBuffer::ReadBEInt16(Int16 & a_Value)
{
CHECK_THREAD
CheckValid();
NEEDBYTES(2);
- Int16 val;
+ UInt16 val;
ReadBuf(&val, 2);
val = ntohs(val);
- a_Value = *(reinterpret_cast<short *>(&val));
+ memcpy(&a_Value, &val, 2);
return true;
}
@@ -373,13 +373,15 @@ bool cByteBuffer::ReadBEUInt16(UInt16 & a_Value)
-bool cByteBuffer::ReadBEInt(int & a_Value)
+bool cByteBuffer::ReadBEInt32(Int32 & a_Value)
{
CHECK_THREAD
CheckValid();
NEEDBYTES(4);
- ReadBuf(&a_Value, 4);
- a_Value = (int)ntohl((u_long)a_Value);
+ UInt32 val;
+ ReadBuf(&val, 4);
+ val = ntohl(val);
+ memcpy(&a_Value, &val, 4);
return true;
}
@@ -415,6 +417,20 @@ bool cByteBuffer::ReadBEInt64(Int64 & a_Value)
+bool cByteBuffer::ReadBEUInt64(UInt64 & a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+ NEEDBYTES(8);
+ ReadBuf(&a_Value, 8);
+ a_Value = NetworkToHostULong8(&a_Value);
+ return true;
+}
+
+
+
+
+
bool cByteBuffer::ReadBEFloat(float & a_Value)
{
CHECK_THREAD
@@ -448,7 +464,7 @@ bool cByteBuffer::ReadBool(bool & a_Value)
CHECK_THREAD
CheckValid();
NEEDBYTES(1);
- char Value = 0;
+ UInt8 Value = 0;
ReadBuf(&Value, 1);
a_Value = (Value != 0);
return true;
@@ -462,24 +478,19 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
{
CHECK_THREAD
CheckValid();
- short Length;
- if (!ReadBEShort(Length))
+ UInt16 Length;
+ if (!ReadBEUInt16(Length))
{
return false;
}
- if (Length < 0)
- {
- ASSERT(!"Negative string length? Are you sure?");
- return true;
- }
- return ReadUTF16String(a_Value, (size_t)Length);
+ return ReadUTF16String(a_Value, Length);
}
-bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
+bool cByteBuffer::ReadVarInt32(UInt32 & a_Value)
{
CHECK_THREAD
CheckValid();
@@ -490,7 +501,29 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
{
NEEDBYTES(1);
ReadBuf(&b, 1);
- Value = Value | (((UInt32)(b & 0x7f)) << Shift);
+ Value = Value | ((static_cast<UInt32>(b & 0x7f)) << Shift);
+ Shift += 7;
+ } while ((b & 0x80) != 0);
+ a_Value = Value;
+ return true;
+}
+
+
+
+
+
+bool cByteBuffer::ReadVarInt64(UInt64 & a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+ UInt64 Value = 0;
+ int Shift = 0;
+ unsigned char b = 0;
+ do
+ {
+ NEEDBYTES(1);
+ ReadBuf(&b, 1);
+ Value = Value | ((static_cast<UInt64>(b & 0x7f)) << Shift);
Shift += 7;
} while ((b & 0x80) != 0);
a_Value = Value;
@@ -540,7 +573,7 @@ bool cByteBuffer::ReadLEInt(int & a_Value)
-bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
+bool cByteBuffer::ReadPosition64(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
{
CHECK_THREAD
Int64 Value;
@@ -565,7 +598,7 @@ bool cByteBuffer::ReadPosition(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
-bool cByteBuffer::WriteChar(char a_Value)
+bool cByteBuffer::WriteBEInt8(Int8 a_Value)
{
CHECK_THREAD
CheckValid();
@@ -577,7 +610,7 @@ bool cByteBuffer::WriteChar(char a_Value)
-bool cByteBuffer::WriteByte(unsigned char a_Value)
+bool cByteBuffer::WriteBEUInt8(UInt8 a_Value)
{
CHECK_THREAD
CheckValid();
@@ -589,33 +622,48 @@ bool cByteBuffer::WriteByte(unsigned char a_Value)
-bool cByteBuffer::WriteBEShort(short a_Value)
+bool cByteBuffer::WriteBEInt16(Int16 a_Value)
{
CHECK_THREAD
CheckValid();
PUTBYTES(2);
- u_short Converted = htons((u_short)a_Value);
- return WriteBuf(&Converted, 2);
+ UInt16 val;
+ memcpy(&val, &a_Value, 2);
+ val = htons(val);
+ return WriteBuf(&val, 2);
}
-bool cByteBuffer::WriteBEUShort(unsigned short a_Value)
+bool cByteBuffer::WriteBEUInt16(UInt16 a_Value)
{
CHECK_THREAD
CheckValid();
PUTBYTES(2);
- u_short Converted = htons((u_short)a_Value);
- return WriteBuf(&Converted, 2);
+ a_Value = htons(a_Value);
+ return WriteBuf(&a_Value, 2);
}
-bool cByteBuffer::WriteBEInt(int a_Value)
+bool cByteBuffer::WriteBEInt32(Int32 a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+ PUTBYTES(4);
+ UInt32 Converted = HostToNetwork4(&a_Value);
+ return WriteBuf(&Converted, 4);
+}
+
+
+
+
+
+bool cByteBuffer::WriteBEUInt32(UInt32 a_Value)
{
CHECK_THREAD
CheckValid();
@@ -641,6 +689,19 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
+bool cByteBuffer::WriteBEUInt64(UInt64 a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+ PUTBYTES(8);
+ UInt64 Converted = HostToNetwork8(&a_Value);
+ return WriteBuf(&Converted, 8);
+}
+
+
+
+
+
bool cByteBuffer::WriteBEFloat(float a_Value)
{
CHECK_THREAD
@@ -672,14 +733,15 @@ bool cByteBuffer::WriteBool(bool a_Value)
{
CHECK_THREAD
CheckValid();
- return WriteChar(a_Value ? 1 : 0);
+ UInt8 val = a_Value ? 1 : 0;
+ return Write(&val, 1);
}
-bool cByteBuffer::WriteVarInt(UInt32 a_Value)
+bool cByteBuffer::WriteVarInt32(UInt32 a_Value)
{
CHECK_THREAD
CheckValid();
@@ -700,12 +762,35 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value)
+
+bool cByteBuffer::WriteVarInt64(UInt64 a_Value)
+{
+ CHECK_THREAD
+ CheckValid();
+
+ // A 64-bit integer can be encoded by at most 10 bytes:
+ unsigned char b[10];
+ size_t idx = 0;
+ do
+ {
+ b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
+ a_Value = a_Value >> 7;
+ idx++;
+ } while (a_Value > 0);
+
+ return WriteBuf(b, idx);
+}
+
+
+
+
+
bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
{
CHECK_THREAD
CheckValid();
PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early.
- bool res = WriteVarInt((UInt32)(a_Value.size()));
+ bool res = WriteVarInt32(static_cast<UInt32>(a_Value.size()));
if (!res)
{
return false;
@@ -717,15 +802,15 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
-bool cByteBuffer::WriteLEInt(int a_Value)
+bool cByteBuffer::WriteLEInt32(Int32 a_Value)
{
CHECK_THREAD
CheckValid();
#ifdef IS_LITTLE_ENDIAN
- return WriteBuf((const char *)&a_Value, 4);
+ return WriteBuf(reinterpret_cast<const char *>(&a_Value), 4);
#else
int Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000);
- return WriteBuf((const char *)&Value, 4);
+ return WriteBuf(reinterpret_cast<const char *>(&Value), 4);
#endif
}
@@ -733,10 +818,15 @@ bool cByteBuffer::WriteLEInt(int a_Value)
-bool cByteBuffer::WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ)
+bool cByteBuffer::WritePosition64(Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ)
{
CHECK_THREAD
- return WriteBEInt64(((Int64)a_BlockX & 0x3FFFFFF) << 38 | ((Int64)a_BlockY & 0xFFF) << 26 | ((Int64)a_BlockZ & 0x3FFFFFF));
+ CheckValid();
+ return WriteBEInt64(
+ (static_cast<Int64>(a_BlockX & 0x3FFFFFF) << 38) |
+ (static_cast<Int64>(a_BlockY & 0xFFF) << 26) |
+ (static_cast<Int64>(a_BlockZ & 0x3FFFFFF))
+ );
}
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index f480ad557..0a4935327 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -52,48 +52,53 @@ public:
bool CanWriteBytes(size_t a_Count) const;
// Read the specified datatype and advance the read pointer; return true if successfully read:
- bool ReadChar (char & a_Value);
- bool ReadByte (unsigned char & a_Value);
- bool ReadBEShort (short & a_Value);
+ bool ReadBEInt8 (Int8 & a_Value);
+ bool ReadBEInt16 (Int16 & a_Value);
+ bool ReadBEInt32 (Int32 & a_Value);
+ bool ReadBEInt64 (Int64 & a_Value);
+ bool ReadBEUInt8 (UInt8 & a_Value);
bool ReadBEUInt16 (UInt16 & a_Value);
- bool ReadBEInt (int & a_Value);
bool ReadBEUInt32 (UInt32 & a_Value);
- bool ReadBEInt64 (Int64 & a_Value);
+ bool ReadBEUInt64 (UInt64 & a_Value);
bool ReadBEFloat (float & a_Value);
bool ReadBEDouble (double & a_Value);
bool ReadBool (bool & a_Value);
bool ReadBEUTF16String16(AString & a_Value); // string length as BE short, then string as UTF-16BE
- bool ReadVarInt (UInt32 & a_Value);
+ bool ReadVarInt32 (UInt32 & a_Value);
+ bool ReadVarInt64 (UInt64 & a_Value);
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
bool ReadLEInt (int & a_Value);
- bool ReadPosition (int & a_BlockX, int & a_BlockY, int & a_BlockZ);
+ bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ);
- /** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */
+ /** Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short, char, Byte, double, ...) */
template <typename T> bool ReadVarInt(T & a_Value)
{
- UInt32 v;
- bool res = ReadVarInt(v);
+ UInt64 v;
+ bool res = ReadVarInt64(v);
if (res)
{
- a_Value = v;
+ a_Value = static_cast<T>(v);
}
return res;
}
// Write the specified datatype; return true if successfully written
- bool WriteChar (char a_Value);
- bool WriteByte (unsigned char a_Value);
- bool WriteBEShort (short a_Value);
- bool WriteBEUShort (unsigned short a_Value);
- bool WriteBEInt (int a_Value);
+ bool WriteBEInt8 (Int8 a_Value);
+ bool WriteBEInt16 (Int16 a_Value);
+ bool WriteBEInt32 (Int32 a_Value);
bool WriteBEInt64 (Int64 a_Value);
+ bool WriteBEUInt8 (UInt8 a_Value);
+ bool WriteBEUInt16 (UInt16 a_Value);
+ bool WriteBEUInt32 (UInt32 a_Value);
+ bool WriteBEUInt64 (UInt64 a_Value);
bool WriteBEFloat (float a_Value);
bool WriteBEDouble (double a_Value);
bool WriteBool (bool a_Value);
- bool WriteVarInt (UInt32 a_Value);
+ bool WriteVarInt32 (UInt32 a_Value);
+ bool WriteVarInt64 (UInt64 a_Value);
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
- bool WriteLEInt (int a_Value);
- bool WritePosition (int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool WriteLEInt32 (Int32 a_Value);
+ bool WritePosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ);
/** Reads a_Count bytes into a_Buffer; returns true if successful */
bool ReadBuf(void * a_Buffer, size_t a_Count);
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c39f5f6e6..b91c4f65a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,7 +9,7 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include
set(FOLDERS
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
- WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs
+ WorldStorage Mobs Entities Simulator BlockEntities UI Generating/Prefabs
Noise
)
@@ -318,7 +318,7 @@ if (NOT MSVC)
target_link_libraries(${EXECUTABLE}
OSSupport HTTPServer Bindings Items Blocks Noise
Protocol Generating Generating_Prefabs WorldStorage
- Mobs Entities Simulator UI BlockEntities PolarSSL++
+ Mobs Entities Simulator BlockEntities UI PolarSSL++
)
endif ()
if (WIN32)
diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua
index 648a5711b..19156b537 100644
--- a/src/CheckBasicStyle.lua
+++ b/src/CheckBasicStyle.lua
@@ -101,9 +101,9 @@ local g_ViolationPatterns =
{"&&[^(]+!=", "Add parenthesis around comparison"},
{"!=[^)]+||", "Add parenthesis around comparison"},
{"||[^(]+!=", "Add parenthesis around comparison"},
- {"<[^)T][^)]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
- {"&&[^(]+<", "Add parenthesis around comparison"},
- {"<[^)T][^)]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ {"<[^)>]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ -- Cannot check a < following a && due to functions of the form x fn(y&& a, z<b> c)
+ {"<[^)>]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
{"||[^(]+<", "Add parenthesis around comparison"},
-- Cannot check ">" because of "obj->m_Flag &&". Check at least ">=":
{">=[^)]+&&", "Add parenthesis around comparison"},
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index e05fa4a99..95dc7708e 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -776,10 +776,22 @@ void cChunk::BroadcastPendingBlockChanges(void)
{
return;
}
-
- for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr)
+
+ if (m_PendingSendBlocks.size() >= 10240)
+ {
+ // Resend the full chunk
+ for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr)
+ {
+ m_World->ForceSendChunkTo(m_PosX, m_PosZ, cChunkSender::E_CHUNK_PRIORITY_MEDIUM, (*itr));
+ }
+ }
+ else
{
- (*itr)->SendBlockChanges(m_PosX, m_PosZ, m_PendingSendBlocks);
+ // Only send block changes
+ for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr)
+ {
+ (*itr)->SendBlockChanges(m_PosX, m_PosZ, m_PendingSendBlocks);
+ }
}
m_PendingSendBlocks.clear();
}
@@ -919,7 +931,7 @@ void cChunk::ApplyWeatherToTop()
FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1);
}
}
- else if (cBlockInfo::IsSnowable(TopBlock) && (Height + 1 < cChunkDef::Height))
+ else if (cBlockInfo::IsSnowable(TopBlock) && (Height < cChunkDef::Height - 1))
{
SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0);
}
@@ -1241,7 +1253,7 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB
bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- if ((a_RelY < 0) || (a_RelY > cChunkDef::Height))
+ if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height))
{
LOGWARNING("UnboundedRelSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY);
return false;
@@ -1262,7 +1274,7 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE
bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- if ((a_RelY < 0) || (a_RelY > cChunkDef::Height))
+ if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height))
{
LOGWARNING("UnboundedRelFastSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY);
return false;
@@ -1957,7 +1969,7 @@ void cChunk::RemoveEntity(cEntity * a_Entity)
-bool cChunk::HasEntity(int a_EntityID)
+bool cChunk::HasEntity(UInt32 a_EntityID)
{
for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr)
{
@@ -2015,7 +2027,7 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_
-bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
+bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
{
// The entity list is locked by the parent chunkmap's CS
for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr)
@@ -2802,7 +2814,7 @@ void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char
-void cChunk::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude)
+void cChunk::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude)
{
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
{
@@ -2810,7 +2822,7 @@ void cChunk::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_bl
{
continue;
}
- (*itr)->SendBlockBreakAnim(a_entityID, a_blockX, a_blockY, a_blockZ, a_stage);
+ (*itr)->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage);
} // for itr - LoadedByClient[]
}
diff --git a/src/Chunk.h b/src/Chunk.h
index 1ce862371..e8c60a74b 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -241,7 +241,7 @@ public:
void AddEntity(cEntity * a_Entity);
void RemoveEntity(cEntity * a_Entity);
- bool HasEntity(int a_EntityID);
+ bool HasEntity(UInt32 a_EntityID);
/** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
@@ -251,7 +251,7 @@ public:
bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
- bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
+ bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
/** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */
bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible
@@ -317,7 +317,7 @@ public:
// (Please keep these alpha-sorted)
void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr);
- void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr);
+ void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr);
void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr);
void BroadcastChunkData (cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr);
void BroadcastCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr);
diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp
index 57b27c5e0..80f40d39e 100644
--- a/src/ChunkData.cpp
+++ b/src/ChunkData.cpp
@@ -361,7 +361,7 @@ void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Lengt
}
else
{
- memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
+ memset(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
}
}
}
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 2dd04f801..87da86131 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -373,19 +373,19 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c
-void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude)
+void cChunkMap::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSLayers);
int ChunkX, ChunkZ;
- cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ);
+ cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ);
if (Chunk == nullptr)
{
return;
}
// It's perfectly legal to broadcast packets even to invalid chunks!
- Chunk->BroadcastBlockBreakAnimation(a_entityID, a_blockX, a_blockY, a_blockZ, a_stage, a_Exclude);
+ Chunk->BroadcastBlockBreakAnimation(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage, a_Exclude);
}
@@ -1322,10 +1322,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
cChunkInterface ChunkInterface(this);
- if (a_BlockType == E_BLOCK_AIR)
- {
- BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);
- }
+ BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ);
@@ -1756,7 +1753,7 @@ void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity)
-bool cChunkMap::HasEntity(int a_UniqueID)
+bool cChunkMap::HasEntity(UInt32 a_UniqueID)
{
cCSLock Lock(m_CSLayers);
for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
@@ -2048,7 +2045,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
-bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback)
+bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
{
cCSLock Lock(m_CSLayers);
bool res = false;
@@ -2999,7 +2996,7 @@ bool cChunkMap::cChunkLayer::ForEachEntity(cEntityCallback & a_Callback)
-bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn)
+bool cChunkMap::cChunkLayer::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn)
{
// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found.
for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++)
@@ -3019,7 +3016,7 @@ bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback &
-bool cChunkMap::cChunkLayer::HasEntity(int a_EntityID)
+bool cChunkMap::cChunkLayer::HasEntity(UInt32 a_EntityID)
{
for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++)
{
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index f08d02337..0fac79c84 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -71,7 +71,7 @@ public:
// (Please keep these alpha-sorted)
void BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle);
void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr);
- void BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude = nullptr);
+ void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr);
void BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude);
void BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = nullptr);
void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr);
@@ -217,7 +217,7 @@ public:
void AddEntityIfNotPresent(cEntity * a_Entity);
/** Returns true if the entity with specified ID is present in the chunks */
- bool HasEntity(int a_EntityID);
+ bool HasEntity(UInt32 a_EntityID);
/** Removes the entity from its appropriate chunk */
void RemoveEntity(cEntity * a_Entity);
@@ -236,61 +236,80 @@ public:
/** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
- /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */
- bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible
+ /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
+ Returns true if entity found and callback returned false. */
+ bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback); // Lua-accessible
- /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */
+ /** Calls the callback for each block entity in the specified chunk.
+ Returns true if all block entities processed, false if the callback aborted by returning true. */
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible
- /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */
+ /** Calls the callback for each chest in the specified chunk.
+ Returns true if all chests processed, false if the callback aborted by returning true. */
bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible
- /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */
+ /** Calls the callback for each dispenser in the specified chunk.
+ Returns true if all dispensers processed, false if the callback aborted by returning true. */
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
- /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */
+ /** Calls the callback for each dropper in the specified chunk.
+ Returns true if all droppers processed, false if the callback aborted by returning true. */
bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
- /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */
+ /** Calls the callback for each dropspenser in the specified chunk.
+ Returns true if all dropspensers processed, false if the callback aborted by returning true. */
bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
- /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */
+ /** Calls the callback for each furnace in the specified chunk.
+ Returns true if all furnaces processed, false if the callback aborted by returning true. */
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
+ /** Calls the callback for the block entity at the specified coords.
+ Returns false if there's no block entity at those coords, true if found. */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible
- /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
+ /** Calls the callback for the beacon at the specified coords.
+ Returns false if there's no beacon at those coords, true if found. */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
- /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
+ /** Calls the callback for the chest at the specified coords.
+ Returns false if there's no chest at those coords, true if found. */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
- /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the dispenser at the specified coords.
+ Returns false if there's no dispenser at those coords or callback returns true, returns true if found. */
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the dropper at the specified coords.
+ Returns false if there's no dropper at those coords or callback returns true, returns true if found. */
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the dropspenser at the specified coords.
+ Returns false if there's no dropspenser at those coords or callback returns true, returns true if found. */
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the furnace at the specified coords.
+ Returns false if there's no furnace at those coords or callback returns true, returns true if found. */
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the noteblock at the specified coords.
+ Returns false if there's no noteblock at those coords or callback returns true, returns true if found. */
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the command block at the specified coords.
+ Returns false if there's no command block at those coords or callback returns true, returns true if found. */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the mob head block at the specified coords.
+ Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */
bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible
- /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
+ /** Calls the callback for the flower pot at the specified coords.
+ Returns false if there's no flower pot at those coords or callback returns true, returns true if found. */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Lua-accessible
- /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
+ /** Retrieves the test on the sign at the specified coords.
+ Returns false if there's no sign at those coords, true if found. */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
/** Touches the chunk, causing it to be loaded or generated */
@@ -423,10 +442,10 @@ private:
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
- bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible
+ bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible
/** Returns true if there is an entity with the specified ID within this layer's chunks */
- bool HasEntity(int a_EntityID);
+ bool HasEntity(UInt32 a_EntityID);
protected:
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 2e0e86653..28fccb68e 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -12,12 +12,16 @@
#include "BlockEntities/CommandBlockEntity.h"
#include "BlockEntities/SignEntity.h"
#include "UI/Window.h"
+#include "UI/AnvilWindow.h"
+#include "UI/BeaconWindow.h"
+#include "UI/EnchantingWindow.h"
#include "Item.h"
#include "Mobs/Monster.h"
#include "ChatColor.h"
#include "Items/ItemHandler.h"
#include "Blocks/BlockHandler.h"
#include "Blocks/BlockSlab.h"
+#include "Blocks/BlockBed.h"
#include "Blocks/ChunkInterface.h"
#include "Root.h"
@@ -672,7 +676,7 @@ bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Usernam
-void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem)
+void cClientHandle::HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction)
{
// This is for creative Inventory changes
if (!m_Player->IsGameModeCreative())
@@ -686,18 +690,18 @@ void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_Hel
return;
}
- m_Player->GetWindow()->Clicked(*m_Player, 0, a_SlotNum, (a_SlotNum >= 0) ? caLeftClick : caLeftClickOutside, a_HeldItem);
+ m_Player->GetWindow()->Clicked(*m_Player, 0, a_SlotNum, a_ClickAction, a_HeldItem);
}
-void cClientHandle::HandleEnchantItem(Byte a_WindowID, Byte a_Enchantment)
+void cClientHandle::HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment)
{
if (a_Enchantment > 2)
{
- LOGWARNING("%s attempt to crash the server with invalid enchanting selection!", GetUsername().c_str());
+ LOGWARNING("%s attempt to crash the server with invalid enchanting selection (%u)!", GetUsername().c_str(), a_Enchantment);
Kick("Invalid enchanting!");
return;
}
@@ -947,7 +951,7 @@ void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, in
-void cClientHandle::HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand)
+void cClientHandle::HandleCommandBlockEntityChange(UInt32 a_EntityID, const AString & a_NewCommand)
{
// TODO
LOGWARNING("%s: Not implemented yet", __FUNCTION__);
@@ -974,7 +978,7 @@ void cClientHandle::HandleAnvilItemName(const AString & a_ItemName)
-void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status)
+void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status)
{
LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i",
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
@@ -1002,6 +1006,12 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
int BlockY = a_BlockY;
int BlockZ = a_BlockZ;
AddFaceDirection(BlockX, BlockY, BlockZ, a_BlockFace);
+
+ if ((BlockY < 0) || (BlockY >= cChunkDef::Height))
+ {
+ return;
+ }
+
if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(BlockX, BlockY, BlockZ))->IsClickedThrough())
{
a_BlockX = BlockX;
@@ -1498,30 +1508,6 @@ void cClientHandle::HandleAnimation(int a_Animation)
return;
}
- // Because the animation ID sent to servers by clients are different to those sent back, we need this
- switch (a_Animation)
- {
- case 0: // No animation - wiki.vg doesn't say that client has something specific for it, so I suppose it will just become -1
- case 1:
- case 2:
- case 3:
- {
- a_Animation--; // Offset by -1
- break;
- }
- case 5:
- case 6:
- case 7:
- {
- a_Animation -= 2; // Offset by -2
- break;
- }
- default: // Anything else is the same
- {
- break;
- }
- }
-
m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, a_Animation, this);
}
@@ -1529,7 +1515,7 @@ void cClientHandle::HandleAnimation(int a_Animation)
-void cClientHandle::HandleSlotSelected(short a_SlotNum)
+void cClientHandle::HandleSlotSelected(Int16 a_SlotNum)
{
m_Player->GetInventory().SetEquippedSlotNum(a_SlotNum);
m_Player->GetWorld()->BroadcastEntityEquipment(*m_Player, 0, m_Player->GetInventory().GetEquippedItem(), this);
@@ -1548,7 +1534,7 @@ void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways)
-void cClientHandle::HandleWindowClose(char a_WindowID)
+void cClientHandle::HandleWindowClose(UInt8 a_WindowID)
{
m_Player->CloseWindowIfID(a_WindowID);
}
@@ -1557,7 +1543,7 @@ void cClientHandle::HandleWindowClose(char a_WindowID)
-void cClientHandle::HandleWindowClick(char a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem)
+void cClientHandle::HandleWindowClick(UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem)
{
LOGD("WindowClick: WinID %d, SlotNum %d, action: %s, Item %s x %d",
a_WindowID, a_SlotNum, ClickActionToString(a_ClickAction),
@@ -1595,7 +1581,7 @@ void cClientHandle::HandleUpdateSign(
-void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick)
+void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
{
// TODO: Let plugins interfere via a hook
@@ -1740,7 +1726,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
-void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
+void cClientHandle::HandleEntityCrouch(UInt32 a_EntityID, bool a_IsCrouching)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -1755,7 +1741,7 @@ void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
-void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
+void cClientHandle::HandleEntityLeaveBed(UInt32 a_EntityID)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -1763,14 +1749,16 @@ void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
return;
}
- m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
+ cChunkInterface Interface(GetPlayer()->GetWorld()->GetChunkMap());
+ cBlockBedHandler::SetBedOccupationState(Interface, GetPlayer()->GetLastBedPos(), false);
+ GetPlayer()->SetIsInBed(false);
}
-void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting)
+void cClientHandle::HandleEntitySprinting(UInt32 a_EntityID, bool a_IsSprinting)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -2042,7 +2030,7 @@ void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, ch
-void cClientHandle::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
+void cClientHandle::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
m_Protocol->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage);
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 8129d6a50..9e5287985 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -144,7 +144,7 @@ public: // tolua_export
// (Please keep these alpha-sorted)
void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType);
- void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
+ void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export
void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes);
void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
@@ -276,16 +276,18 @@ public: // tolua_export
/** Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new
command in the command block UI, for an entity-based commandblock (minecart?). */
- void HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand);
+ void HandleCommandBlockEntityChange(UInt32 a_EntityID, const AString & a_NewCommand);
- void HandleCreativeInventory (short a_SlotNum, const cItem & a_HeldItem);
+ /** Called when the client clicks the creative inventory window.
+ a_ClickAction specifies whether the click was inside the window or not (caLeftClick or caLeftClickOutside). */
+ void HandleCreativeInventory(Int16 a_SlotNum, const cItem & a_HeldItem, eClickAction a_ClickAction);
/** Called when the player enchants an Item in the Enchanting table UI. */
- void HandleEnchantItem(Byte a_WindowID, Byte a_Enchantment);
+ void HandleEnchantItem(UInt8 a_WindowID, UInt8 a_Enchantment);
- void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
- void HandleEntityLeaveBed (int a_EntityID);
- void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
+ void HandleEntityCrouch (UInt32 a_EntityID, bool a_IsCrouching);
+ void HandleEntityLeaveBed (UInt32 a_EntityID);
+ void HandleEntitySprinting (UInt32 a_EntityID, bool a_IsSprinting);
/** Kicks the client if the same username is already logged in.
Returns false if the client has been kicked, true otherwise. */
@@ -298,7 +300,7 @@ public: // tolua_export
bool HandleHandshake (const AString & a_Username);
void HandleKeepAlive (int a_KeepAliveID);
- void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status);
+ void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, UInt8 a_Status);
/** Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in
the NPC UI. */
@@ -312,7 +314,7 @@ public: // tolua_export
void HandlePluginMessage (const AString & a_Channel, const AString & a_Message);
void HandleRespawn (void);
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
- void HandleSlotSelected (short a_SlotNum);
+ void HandleSlotSelected (Int16 a_SlotNum);
void HandleSteerVehicle (float Forward, float Sideways);
void HandleTabCompletion (const AString & a_Text);
void HandleUpdateSign (
@@ -321,9 +323,9 @@ public: // tolua_export
const AString & a_Line3, const AString & a_Line4
);
void HandleUnmount (void);
- void HandleUseEntity (int a_TargetEntityID, bool a_IsLeftClick);
- void HandleWindowClick (char a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem);
- void HandleWindowClose (char a_WindowID);
+ void HandleUseEntity (UInt32 a_TargetEntityID, bool a_IsLeftClick);
+ void HandleWindowClick (UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem);
+ void HandleWindowClose (UInt8 a_WindowID);
/** Called when the protocol has finished logging the user in.
Return true to allow the user in; false to kick them.
diff --git a/src/Endianness.h b/src/Endianness.h
index 9aeb44986..ed9637fcc 100644
--- a/src/Endianness.h
+++ b/src/Endianness.h
@@ -2,7 +2,7 @@
#pragma once
#undef ntohll
-#define ntohll(x) ((((UInt64)ntohl((u_long)x)) << 32) + ntohl(x >> 32))
+#define ntohll(x) ((((UInt64)ntohl((UInt32)x)) << 32) + ntohl(x >> 32))
@@ -11,10 +11,10 @@
// Changes endianness
inline UInt64 HostToNetwork8(const void * a_Value)
{
- unsigned long long __HostToNetwork8;
- memcpy( &__HostToNetwork8, a_Value, sizeof( __HostToNetwork8));
- __HostToNetwork8 = (( ( (unsigned long long)htonl((u_long)__HostToNetwork8)) << 32) + htonl(__HostToNetwork8 >> 32));
- return __HostToNetwork8;
+ UInt64 buf;
+ memcpy( &buf, a_Value, sizeof( buf));
+ buf = (( ( (UInt64)htonl((UInt32)buf)) << 32) + htonl(buf >> 32));
+ return buf;
}
@@ -23,10 +23,10 @@ inline UInt64 HostToNetwork8(const void * a_Value)
inline UInt32 HostToNetwork4(const void* a_Value)
{
- unsigned int __HostToNetwork4;
- memcpy( &__HostToNetwork4, a_Value, sizeof( __HostToNetwork4));
- __HostToNetwork4 = ntohl( __HostToNetwork4);
- return __HostToNetwork4;
+ UInt32 buf;
+ memcpy( &buf, a_Value, sizeof( buf));
+ buf = ntohl( buf);
+ return buf;
}
@@ -59,6 +59,18 @@ inline Int64 NetworkToHostLong8(const void * a_Value)
+inline UInt64 NetworkToHostULong8(const void * a_Value)
+{
+ UInt64 buf;
+ memcpy(&buf, a_Value, 8);
+ buf = ntohll(buf);
+ return buf;
+}
+
+
+
+
+
inline float NetworkToHostFloat4(const void * a_Value)
{
UInt32 buf;
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
index 0fbbfb681..3c1fabb1b 100644
--- a/src/Entities/ArrowEntity.cpp
+++ b/src/Entities/ArrowEntity.cpp
@@ -72,14 +72,8 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
- if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001))
- {
- SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later
- }
-
Vector3d Hit = a_HitPos;
- Vector3d SinkMovement = (GetSpeed() / 1000);
- Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
+ Hit += GetSpeed().NormalizeCopy() / 100000; // Make arrow sink into block a bit so it lodges (TODO: investigate how to stop them going so far so that they become black clientside)
super::OnHitSolidBlock(Hit, a_HitFace);
Vector3i BlockHit = Hit.Floor();
@@ -195,11 +189,6 @@ void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (m_IsInGround)
{
- // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
- // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
- // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
- // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
-
if (!m_HasTeleported) // Sent a teleport already, don't do again
{
if (m_HitGroundTimer > std::chrono::milliseconds(500))
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 6d8b4ef31..6177eb32f 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -98,7 +98,7 @@ void cBoat::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed
- if ((POSY_TOINT < 0) || (POSY_TOINT > cChunkDef::Height))
+ if ((POSY_TOINT < 0) || (POSY_TOINT >= cChunkDef::Height))
{
return;
}
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 1bc4690e1..c8df6b4b1 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -18,49 +18,50 @@
-int cEntity::m_EntityCount = 0;
+UInt32 cEntity::m_EntityCount = 0;
cCriticalSection cEntity::m_CSCount;
-cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height)
- : m_UniqueID(0)
- , m_Health(1)
- , m_MaxHealth(1)
- , m_AttachedTo(nullptr)
- , m_Attachee(nullptr)
- , m_bDirtyHead(true)
- , m_bDirtyOrientation(true)
- , m_bHasSentNoSpeed(true)
- , m_bOnGround(false)
- , m_Gravity(-9.81f)
- , m_LastPos(a_X, a_Y, a_Z)
- , m_IsInitialized(false)
- , m_WorldTravellingFrom(nullptr)
- , m_EntityType(a_EntityType)
- , m_World(nullptr)
- , m_IsFireproof(false)
- , m_TicksSinceLastBurnDamage(0)
- , m_TicksSinceLastLavaDamage(0)
- , m_TicksSinceLastFireDamage(0)
- , m_TicksLeftBurning(0)
- , m_TicksSinceLastVoidDamage(0)
- , m_IsSwimming(false)
- , m_IsSubmerged(false)
- , m_AirLevel(0)
- , m_AirTickTimer(0)
- , m_TicksAlive(0)
- , m_HeadYaw(0.0)
- , m_Rot(0.0, 0.0, 0.0)
- , m_Pos(a_X, a_Y, a_Z)
- , m_WaterSpeed(0, 0, 0)
- , m_Mass (0.001) // Default 1g
- , m_Width(a_Width)
- , m_Height(a_Height)
- , m_InvulnerableTicks(0)
-{
+cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height):
+ m_UniqueID(INVALID_ID), // Proper ID will be assigned later in the constructor code
+ m_Health(1),
+ m_MaxHealth(1),
+ m_AttachedTo(nullptr),
+ m_Attachee(nullptr),
+ m_bDirtyHead(true),
+ m_bDirtyOrientation(true),
+ m_bHasSentNoSpeed(true),
+ m_bOnGround(false),
+ m_Gravity(-9.81f),
+ m_LastPos(a_X, a_Y, a_Z),
+ m_IsInitialized(false),
+ m_WorldTravellingFrom(nullptr),
+ m_EntityType(a_EntityType),
+ m_World(nullptr),
+ m_IsFireproof(false),
+ m_TicksSinceLastBurnDamage(0),
+ m_TicksSinceLastLavaDamage(0),
+ m_TicksSinceLastFireDamage(0),
+ m_TicksLeftBurning(0),
+ m_TicksSinceLastVoidDamage(0),
+ m_IsSwimming(false),
+ m_IsSubmerged(false),
+ m_AirLevel(0),
+ m_AirTickTimer(0),
+ m_TicksAlive(0),
+ m_HeadYaw(0.0),
+ m_Rot(0.0, 0.0, 0.0),
+ m_Pos(a_X, a_Y, a_Z),
+ m_WaterSpeed(0, 0, 0),
+ m_Mass (0.001), // Default 1g
+ m_Width(a_Width),
+ m_Height(a_Height),
+ m_InvulnerableTicks(0)
+{
+ // Assign a proper ID:
cCSLock Lock(m_CSCount);
m_EntityCount++;
m_UniqueID = m_EntityCount;
@@ -1263,7 +1264,7 @@ bool cEntity::DetectPortal()
{
if (GetWorld()->GetDimension() == dimOverworld)
{
- if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty())
+ if (GetWorld()->GetLinkedNetherWorldName().empty() && GetWorld()->GetLinkedEndWorldName().empty())
{
// Teleportation to either dimension not enabled, don't bother proceeding
return false;
@@ -1314,7 +1315,7 @@ bool cEntity::DetectPortal()
}
else
{
- if (GetWorld()->GetNetherWorldName().empty())
+ if (GetWorld()->GetLinkedNetherWorldName().empty())
{
return false;
}
@@ -1327,7 +1328,7 @@ bool cEntity::DetectPortal()
((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether);
}
- return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false);
+ return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedNetherWorldName(), dimNether, GetWorld()->GetName()), false);
}
}
case E_BLOCK_END_PORTAL:
@@ -1358,7 +1359,7 @@ bool cEntity::DetectPortal()
}
else
{
- if (GetWorld()->GetEndWorldName().empty())
+ if (GetWorld()->GetLinkedEndWorldName().empty())
{
return false;
}
@@ -1371,7 +1372,7 @@ bool cEntity::DetectPortal()
((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd);
}
- return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false);
+ return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedEndWorldName(), dimEnd, GetWorld()->GetName()), false);
}
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 809e974d2..9bb1837f1 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -142,6 +142,10 @@ public:
static const int VOID_BOUNDARY = -46; ///< Y position to begin applying void damage
static const int FALL_DAMAGE_HEIGHT = 4; ///< Y difference after which fall damage is applied
+
+ /** Special ID that is considered an "invalid value", signifying no entity. */
+ static const UInt32 INVALID_ID = 0; // Exported to Lua in ManualBindings.cpp, ToLua doesn't parse initialized constants.
+
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
virtual ~cEntity();
@@ -248,7 +252,7 @@ public:
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways);
void SteerVehicle(float a_Forward, float a_Sideways);
- inline int GetUniqueID(void) const { return m_UniqueID; }
+ inline UInt32 GetUniqueID(void) const { return m_UniqueID; }
inline bool IsDestroyed(void) const { return !m_IsInitialized; }
/// Schedules the entity for destroying; if a_ShouldBroadcast is set to true, broadcasts the DestroyEntity packet
@@ -464,12 +468,15 @@ public:
protected:
static cCriticalSection m_CSCount;
- static int m_EntityCount;
+ static UInt32 m_EntityCount;
/** Measured in meter/second (m/s) */
Vector3d m_Speed;
- int m_UniqueID;
+ /** The ID of the entity that is guaranteed to be unique within a single run of the server.
+ Always nonzero (a zero UniqueID (cEntity::INVALID_ID) is used for error reporting).
+ Note that the UniqueID is not persisted through storage. */
+ UInt32 m_UniqueID;
int m_Health;
int m_MaxHealth;
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index 75105a0cd..7301a3c9d 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -77,7 +77,10 @@ void cFallingBlock::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
);
*/
- cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta);
+ if (BlockY < cChunkDef::Height - 1)
+ {
+ cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta);
+ }
Destroy(true);
return;
}
diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp
index a6b9c40c8..a37d8702e 100644
--- a/src/Entities/HangingEntity.cpp
+++ b/src/Entities/HangingEntity.cpp
@@ -11,7 +11,7 @@
cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, double a_X, double a_Y, double a_Z) :
cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8),
- m_Facing(a_Facing)
+ m_Facing(cHangingEntity::BlockFaceToProtocolFace(a_Facing))
{
SetMaxHealth(1);
SetHealth(1);
@@ -21,60 +21,9 @@ cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, do
-void cHangingEntity::SetFacing(eBlockFace a_Facing)
-{
- // Y-based faces are not allowed:
- switch (a_Facing)
- {
- case BLOCK_FACE_NONE:
- case BLOCK_FACE_YM:
- case BLOCK_FACE_YP:
- {
- LOGWARNING("%s: Invalid facing: %d. Ignoring.", __FUNCTION__, a_Facing);
- ASSERT(!"Tried to set a bad facing!");
- return;
- }
- default: break;
- }
-
- m_Facing = a_Facing;
-}
-
-
-
-
-
void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
- int Dir = 0;
-
- // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
- switch (m_Facing)
- {
- case BLOCK_FACE_ZP: Dir = 0; break;
- case BLOCK_FACE_ZM: Dir = 2; break;
- case BLOCK_FACE_XM: Dir = 1; break;
- case BLOCK_FACE_XP: Dir = 3; break;
- default:
- {
- LOGINFO("Invalid facing (%d) in a cHangingEntity at {%d, %d, %d}, adjusting to BLOCK_FACE_XP.",
- m_Facing, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ()
- );
- Dir = 3;
- }
- }
-
- if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
- {
- SetYaw((Dir * 90) - 180);
- }
- else
- {
- SetYaw(Dir * 90);
- }
-
- a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
- a_ClientHandle.SendEntityMetadata(*this);
+ SetYaw(GetProtocolFacing() * 90);
}
diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h
index d1ef79a68..507502ac6 100644
--- a/src/Entities/HangingEntity.h
+++ b/src/Entities/HangingEntity.h
@@ -24,28 +24,82 @@ public:
// tolua_begin
/** Returns the direction in which the entity is facing. */
- eBlockFace GetFacing() const { return m_Facing; }
-
+ eBlockFace GetFacing() const { return cHangingEntity::ProtocolFaceToBlockFace(m_Facing); }
+
/** Set the direction in which the entity is facing. */
- void SetFacing(eBlockFace a_Facing);
-
- /** Returns the X coord of the block in which the entity resides. */
- int GetBlockX() const { return POSX_TOINT; }
-
- /** Returns the Y coord of the block in which the entity resides. */
- int GetBlockY() const { return POSY_TOINT; }
-
- /** Returns the Z coord of the block in which the entity resides. */
- int GetBlockZ() const { return POSZ_TOINT; }
+ void SetFacing(eBlockFace a_Facing) { m_Facing = cHangingEntity::BlockFaceToProtocolFace(a_Facing); }
// tolua_end
-private:
+ /** Returns the direction in which the entity is facing. */
+ Byte GetProtocolFacing() const { return m_Facing; }
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
- virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override {}
+ /** Set the direction in which the entity is facing. */
+ void SetProtocolFacing(Byte a_Facing)
+ {
+ ASSERT((a_Facing <= 3) && (a_Facing >= 0));
+ m_Facing = a_Facing;
+ }
- eBlockFace m_Facing;
+protected:
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override
+ {
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
+ }
+
+ /** Converts protocol hanging item facing to eBlockFace values */
+ inline static eBlockFace ProtocolFaceToBlockFace(Byte a_ProtocolFace)
+ {
+ eBlockFace Dir;
+
+ // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
+ switch (a_ProtocolFace)
+ {
+ case 0: Dir = BLOCK_FACE_ZP; break;
+ case 2: Dir = BLOCK_FACE_ZM; break;
+ case 1: Dir = BLOCK_FACE_XM; break;
+ case 3: Dir = BLOCK_FACE_XP; break;
+ default:
+ {
+ LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_ProtocolFace);
+ ASSERT(!"Tried to convert a bad facing!");
+
+ Dir = cHangingEntity::ProtocolFaceToBlockFace(3);
+ }
+ }
+
+ return Dir;
+ }
+
+ /** Converts eBlockFace values to protocol hanging item faces */
+ inline static Byte BlockFaceToProtocolFace(eBlockFace a_BlockFace)
+ {
+ Byte Dir;
+
+ // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_ZP: Dir = 0; break;
+ case BLOCK_FACE_ZM: Dir = 2; break;
+ case BLOCK_FACE_XM: Dir = 1; break;
+ case BLOCK_FACE_XP: Dir = 3; break;
+ default:
+ {
+ // Uncomment when entities are initialised with their real data, instead of dummy values:
+ // LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_BlockFace);
+ // ASSERT(!"Tried to convert a bad facing!");
+
+ Dir = cHangingEntity::BlockFaceToProtocolFace(BLOCK_FACE_XP);
+ }
+ }
+
+ return Dir;
+ }
+
+ Byte m_Facing;
}; // tolua_export
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index dfffcd3ed..4e6e38f1f 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -92,3 +92,14 @@ void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer)
+
+void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ super::SpawnOn(a_ClientHandle);
+ a_ClientHandle.SendSpawnObject(*this, 71, GetProtocolFacing(), (Byte)GetYaw(), (Byte)GetPitch());
+ a_ClientHandle.SendEntityMetadata(*this);
+}
+
+
+
+
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
index ced8c37af..ff43e5ee1 100644
--- a/src/Entities/ItemFrame.h
+++ b/src/Entities/ItemFrame.h
@@ -24,7 +24,7 @@ public:
// tolua_begin
/** Returns the item in the frame */
- const cItem & GetItem(void) { return m_Item; }
+ const cItem & GetItem(void) const { return m_Item; }
/** Set the item in the frame */
void SetItem(cItem & a_Item) { m_Item = a_Item; }
@@ -42,6 +42,7 @@ private:
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
cItem m_Item;
Byte m_ItemRotation;
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 776f957f4..ee10cf6b3 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -11,6 +11,7 @@
#include "../Chunk.h"
#include "Player.h"
#include "../BoundingBox.h"
+#include "../UI/MinecartWithChestWindow.h"
#define NO_SPEED 0.0
#define MAX_SPEED 8
@@ -23,7 +24,7 @@ class cMinecartCollisionCallback :
public cEntityCallback
{
public:
- cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, int a_UniqueID, int a_AttacheeUniqueID) :
+ cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, UInt32 a_UniqueID, UInt32 a_AttacheeUniqueID) :
m_DoesInteserct(false),
m_CollidedEntityPos(0, 0, 0),
m_Pos(a_Pos),
@@ -76,8 +77,8 @@ protected:
Vector3d m_Pos;
double m_Height, m_Width;
- int m_UniqueID;
- int m_AttacheeUniqueID;
+ UInt32 m_UniqueID;
+ UInt32 m_AttacheeUniqueID;
};
@@ -823,7 +824,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
{
- cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == nullptr) ? -1 : m_Attachee->GetUniqueID()));
+ cMinecartCollisionCallback MinecartCollisionCallback(
+ GetPosition(), GetHeight(), GetWidth(), GetUniqueID(),
+ ((m_Attachee == nullptr) ? cEntity::INVALID_ID : m_Attachee->GetUniqueID())
+ );
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback);
diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp
index 6f6277f28..02a8f6ed0 100644
--- a/src/Entities/Painting.cpp
+++ b/src/Entities/Painting.cpp
@@ -10,10 +10,9 @@
-cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z)
- : cEntity(etPainting, a_X, a_Y, a_Z, 1, 1),
- m_Name(a_Name),
- m_Direction(a_Direction)
+cPainting::cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z)
+ : cHangingEntity(etPainting, a_Direction, a_X, a_Y, a_Z),
+ m_Name(a_Name)
{
}
@@ -24,6 +23,7 @@ cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double
void cPainting::SpawnOn(cClientHandle & a_Client)
{
+ super::SpawnOn(a_Client);
a_Client.SendPaintingSpawn(*this);
}
@@ -31,16 +31,6 @@ void cPainting::SpawnOn(cClientHandle & a_Client)
-void cPainting::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
-{
- UNUSED(a_Dt);
- UNUSED(a_Chunk);
-}
-
-
-
-
-
void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
{
if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h
index 6e8a382fc..20968d4f0 100644
--- a/src/Entities/Painting.h
+++ b/src/Entities/Painting.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Entity.h"
+#include "HangingEntity.h"
@@ -9,9 +9,9 @@
// tolua_begin
class cPainting :
- public cEntity
+ public cHangingEntity
{
- typedef cEntity super;
+ typedef cHangingEntity super;
public:
@@ -19,19 +19,14 @@ public:
CLASS_PROTODEF(cPainting)
- cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z);
+ cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z);
- // tolua_begin
-
- const AString & GetName(void) const { return m_Name; }
- int GetDirection(void) const { return m_Direction; }
-
- // tolua_end
+ /** Returns the protocol name of the painting */
+ const AString & GetName(void) const { return m_Name; } // tolua_export
private:
virtual void SpawnOn(cClientHandle & a_Client) override;
- virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override
{
@@ -40,7 +35,6 @@ private:
}
AString m_Name;
- int m_Direction;
}; // tolua_export
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 0d36d0b23..c89e7b87c 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -5,7 +5,7 @@
#include <unordered_map>
#include "../ChatColor.h"
#include "../Server.h"
-#include "../UI/Window.h"
+#include "../UI/InventoryWindow.h"
#include "../UI/WindowOwner.h"
#include "../World.h"
#include "../Bindings/PluginManager.h"
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index e02c66bd3..3dae58dc1 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -314,8 +314,18 @@ public:
// tolua_end
- /** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */
- void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; }
+ /** Sets a player's in-bed state
+ We can't be sure plugins will keep this value updated, so no exporting
+ If value is false (not in bed), will update players of the fact that they have been ejected from the bed
+ */
+ void SetIsInBed(bool a_Flag)
+ {
+ m_bIsInBed = a_Flag;
+ if (!a_Flag)
+ {
+ GetWorld()->BroadcastEntityAnimation(*this, 2);
+ }
+ }
/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void);
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 4f20bfae6..4684e3e09 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -221,7 +221,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
m_ProjectileKind(a_Kind),
m_CreatorData(
- ((a_Creator != nullptr) ? a_Creator->GetUniqueID() : -1),
+ ((a_Creator != nullptr) ? a_Creator->GetUniqueID() : cEntity::INVALID_ID),
((a_Creator != nullptr) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""),
((a_Creator != nullptr) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments())
),
@@ -334,12 +334,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
void cProjectileEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
-
- // TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick())
- if (GetProjectileKind() != pkArrow)
- {
- BroadcastMovementUpdate();
- }
+ BroadcastMovementUpdate();
}
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index 93e442d8c..de460a8ad 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -69,7 +69,7 @@ public:
/** Returns the unique ID of the entity who created this projectile
May return an ID <0
*/
- int GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; }
+ UInt32 GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; }
/** Returns the name of the player that created the projectile
Will be empty for non-player creators
@@ -90,18 +90,17 @@ public:
protected:
/** A structure that stores the Entity ID and Playername of the projectile's creator
- Used to migitate invalid pointers caused by the creator being destroyed
- */
+ Used to migitate invalid pointers caused by the creator being destroyed. */
struct CreatorData
{
- CreatorData(int a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) :
+ CreatorData(UInt32 a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) :
m_UniqueID(a_UniqueID),
m_Name(a_Name),
m_Enchantments(a_Enchantments)
{
}
- const int m_UniqueID;
+ const UInt32 m_UniqueID;
AString m_Name;
cEnchantments m_Enchantments;
};
@@ -110,8 +109,7 @@ protected:
eKind m_ProjectileKind;
/** The structure for containing the entity ID and name who has created this projectile
- The ID and/or name may be nullptr (e.g. for dispensers/mobs)
- */
+ The ID and/or name may be nullptr (e.g. for dispensers/mobs). */
CreatorData m_CreatorData;
/** True if the projectile has hit the ground and is stuck there */
diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp
index 515dc25ea..737b13535 100644
--- a/src/FastRandom.cpp
+++ b/src/FastRandom.cpp
@@ -6,6 +6,12 @@
#include "Globals.h"
#include "FastRandom.h"
+#ifdef _WIN32
+ #define thread_local __declspec(thread)
+#endif
+
+thread_local unsigned int m_Counter = 0;
+
@@ -86,7 +92,7 @@ public:
cFastRandom::cFastRandom(void) :
- m_LinearRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count()))
+ m_LinearRand(m_Counter++)
{
}
@@ -105,18 +111,6 @@ int cFastRandom::NextInt(int a_Range)
-int cFastRandom::NextInt(int a_Range, int a_Salt)
-{
- m_LinearRand.seed(a_Salt);
- std::uniform_int_distribution<> distribution(0, a_Range - 1);
- return distribution(m_LinearRand);
-}
-
-
-
-
-
-
float cFastRandom::NextFloat(float a_Range)
{
std::uniform_real_distribution<float> distribution(0, a_Range);
@@ -128,18 +122,6 @@ float cFastRandom::NextFloat(float a_Range)
-float cFastRandom::NextFloat(float a_Range, int a_Salt)
-{
- m_LinearRand.seed(a_Salt);
- std::uniform_real_distribution<float> distribution(0, a_Range);
- return distribution(m_LinearRand);
-}
-
-
-
-
-
-
int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
{
std::uniform_int_distribution<> distribution(a_Begin, a_End);
@@ -154,7 +136,7 @@ int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
// MTRand:
MTRand::MTRand() :
- m_MersenneRand(static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count()))
+ m_MersenneRand(m_Counter++)
{
}
diff --git a/src/FastRandom.h b/src/FastRandom.h
index 64a087c97..30395a293 100644
--- a/src/FastRandom.h
+++ b/src/FastRandom.h
@@ -36,16 +36,10 @@ public:
/** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */
int NextInt(int a_Range);
-
- /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness */
- int NextInt(int a_Range, int a_Salt);
/** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */
float NextFloat(float a_Range);
- /** 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 float between 0 and 1. */
float NextFloat(void) { return NextFloat(1); }
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 112aa8146..ea952a852 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -291,6 +291,22 @@ const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_In
+bool cFurnaceRecipe::IsFuel(const cItem & a_Item) const
+{
+ for (auto & Fuel : m_pState->Fuel)
+ {
+ if ((Fuel.In->m_ItemType == a_Item.m_ItemType) && (Fuel.In->m_ItemCount <= a_Item.m_ItemCount))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const
{
int BestFuel = 0;
diff --git a/src/FurnaceRecipe.h b/src/FurnaceRecipe.h
index 936ef706d..912b6aba2 100644
--- a/src/FurnaceRecipe.h
+++ b/src/FurnaceRecipe.h
@@ -34,6 +34,9 @@ public:
/** Returns a recipe for the specified input, nullptr if no recipe found */
const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const;
+
+ /** Returns true if the item is a fuel, false if not. */
+ bool IsFuel(const cItem & a_Item) const;
/** Returns the amount of time that the specified fuel burns, in ticks */
int GetBurnTime(const cItem & a_Fuel) const;
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 265db30ad..867155ad2 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -941,21 +941,21 @@ public:
cBioGenGrown(int a_Seed)
{
auto FinalRivers =
- std::make_shared<cIntGenSmooth<8>> (a_Seed + 1,
- std::make_shared<cIntGenZoom <10>> (a_Seed + 2,
- std::make_shared<cIntGenRiver <7>> (a_Seed + 3,
- std::make_shared<cIntGenZoom <9>> (a_Seed + 4,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 8,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 9,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 10,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenSmooth<8>> (a_Seed + 6,
- std::make_shared<cIntGenZoom <10>> (a_Seed + 11,
- std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12
- ))))))))))))));
+
+ std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12)
+ | MakeIntGen<cIntGenZoom <10>>(a_Seed + 11)
+ | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 6)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 10)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 9)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 8)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <9>>(a_Seed + 4)
+ | MakeIntGen<cIntGenRiver <7>>(a_Seed + 3)
+ | MakeIntGen<cIntGenZoom <10>>(a_Seed + 2)
+ | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 1);
auto alteration =
std::make_shared<cIntGenZoom <8>>(a_Seed,
@@ -1000,9 +1000,9 @@ public:
std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150,
std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200,
std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean,
- std::make_shared<cIntGenZoom <6>> (a_Seed + 10,
- std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30
- )))))))))))))))))))))))))))))));
+ std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30)
+ | MakeIntGen<cIntGenZoom <6>> (a_Seed + 10)
+ )))))))))))))))))))))))))))));
m_Gen =
std::make_shared<cIntGenSmooth <16>>(a_Seed,
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 260253d62..5839a4ccc 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -571,7 +571,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
continue;
}
- if (!cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1))
+ if (!cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) || (Height >= cChunkDef::Height - 1))
{
// The top block can't be snown over.
continue;
diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h
index b25e378c0..854563f41 100644
--- a/src/Generating/IntGen.h
+++ b/src/Generating/IntGen.h
@@ -31,6 +31,8 @@ by using templates.
#include "../BiomeDef.h"
+#include <tuple>
+
@@ -53,6 +55,9 @@ template <int SizeX, int SizeZ = SizeX>
class cIntGen
{
public:
+
+ typedef cIntGen<SizeX, SizeZ> IntGenType;
+
/** Force a virtual destructor in all descendants.
Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */
virtual ~cIntGen() {}
@@ -62,9 +67,70 @@ public:
/** Generates the array of templated size into a_Values, based on given min coords. */
virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) = 0;
+
+};
+
+// Code adapted from http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer
+
+template<int... >
+struct sSeq
+{
+};
+
+template<int N, int... S>
+struct sGens : sGens<N - 1, N - 1, S...>
+{
+};
+
+template<int... S>
+struct sGens<0, S...>
+{
+ typedef sSeq<S...> type;
+};
+
+
+template<class Gen, class... Args>
+class cIntGenFactory
+{
+
+public:
+
+ typedef Gen Generator;
+
+ cIntGenFactory(Args&&... a_args) :
+ m_args(std::make_tuple<Args...>(std::forward<Args>(a_args)...))
+ {
+ }
+
+ template <class LhsGen>
+ std::shared_ptr<Gen> construct(LhsGen&& a_Lhs)
+ {
+ return construct_impl<LhsGen>(std::forward<LhsGen>(a_Lhs), typename sGens<sizeof...(Args)>::type());
+ }
+
+
+private:
+ std::tuple<Args...> m_args;
+
+ template <class LhsGen, int... S>
+ std::shared_ptr<Gen> construct_impl(LhsGen&& a_Lhs, sSeq<S...>)
+ {
+ return std::make_shared<Gen>(std::get<S>(m_args)..., std::forward<LhsGen>(a_Lhs));
+ }
+
};
+template<class T, class RhsGen, class... Args>
+std::shared_ptr<RhsGen> operator| (std::shared_ptr<T> a_Lhs, cIntGenFactory<RhsGen, Args...> a_Rhs)
+{
+ return a_Rhs.construct(static_cast<std::shared_ptr<typename T::IntGenType>>(a_Lhs));
+}
+template<class Gen, class... Args>
+cIntGenFactory<Gen, Args...> MakeIntGen(Args&&... a_Args)
+{
+ return cIntGenFactory<Gen, Args...>(std::forward<Args>(a_Args)...);
+}
@@ -688,7 +754,7 @@ public:
int IdxZ = z * SizeX;
for (int x = 0; x < SizeX; x++)
{
- int val = a_Values[x + IdxZ];
+ size_t val = (size_t)a_Values[x + IdxZ];
const cBiomesInGroups & Biomes = (val > bgfRare) ?
rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] :
biomesInGroups[val % ARRAYCOUNT(biomesInGroups)];
diff --git a/src/Generating/ShapeGen.cpp b/src/Generating/ShapeGen.cpp
index 45a9c3b93..43601ee20 100644
--- a/src/Generating/ShapeGen.cpp
+++ b/src/Generating/ShapeGen.cpp
@@ -41,7 +41,7 @@ public:
{
for (int x = 0; x < cChunkDef::Width; x++)
{
- HEIGHTTYPE height = cChunkDef::GetHeight(heightMap, x, z) + 1;
+ int height = cChunkDef::GetHeight(heightMap, x, z) + 1;
Byte * shapeColumn = &(a_Shape[(x + 16 * z) * 256]);
for (int y = 0; y < height; y++)
{
diff --git a/src/Globals.h b/src/Globals.h
index 7c2ab38d8..bd180c08f 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -132,13 +132,15 @@
// Integral types with predefined sizes:
-typedef long long Int64;
-typedef int Int32;
-typedef short Int16;
+typedef signed long long Int64;
+typedef signed int Int32;
+typedef signed short Int16;
+typedef signed char Int8;
typedef unsigned long long UInt64;
typedef unsigned int UInt32;
typedef unsigned short UInt16;
+typedef unsigned char UInt8;
typedef unsigned char Byte;
@@ -156,10 +158,12 @@ class SizeChecker<T, Size, true>
template class SizeChecker<Int64, 8>;
template class SizeChecker<Int32, 4>;
template class SizeChecker<Int16, 2>;
+template class SizeChecker<Int8, 1>;
template class SizeChecker<UInt64, 8>;
template class SizeChecker<UInt32, 4>;
template class SizeChecker<UInt16, 2>;
+template class SizeChecker<UInt8, 1>;
// A macro to disallow the copy constructor and operator = functions
// This should be used in the private: declarations for any class that shouldn't allow copying itself
diff --git a/src/Inventory.h b/src/Inventory.h
index 4e76bc0d3..311f64562 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -31,7 +31,9 @@ You can use the invArmorOffset, invInventoryOffset and invHotbarOffset constants
*/
class cInventory :
+ // tolua_end
public cItemGrid::cListener
+ // tolua_begin
{
public:
diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h
index 71143d5a8..524c49a5c 100644
--- a/src/Items/ItemDoor.h
+++ b/src/Items/ItemDoor.h
@@ -34,7 +34,7 @@ public:
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
// Door (bottom block) can be placed in Y range of [1, 254]:
- if ((a_BlockY < 1) || (a_BlockY + 2 >= cChunkDef::Height))
+ if ((a_BlockY < 1) || (a_BlockY >= cChunkDef::Height - 2))
{
return false;
}
diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h
index a2a77ce21..d6f2e24b4 100644
--- a/src/Items/ItemPainting.h
+++ b/src/Items/ItemPainting.h
@@ -21,30 +21,17 @@ public:
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
- if (a_Dir == BLOCK_FACE_NONE)
+ if ((a_Dir == BLOCK_FACE_NONE) || (a_Dir == BLOCK_FACE_YM) || (a_Dir == BLOCK_FACE_YP))
{
- // Client sends this if clicked on top or bottom face
+ // Paintings can't be flatly placed
return false;
}
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again
if (Block == E_BLOCK_AIR)
{
- int Dir = 0;
-
- // The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces
- switch (a_Dir)
- {
- case BLOCK_FACE_ZP: break; // Initialised to zero
- case BLOCK_FACE_ZM: Dir = 2; break;
- case BLOCK_FACE_XM: Dir = 1; break;
- case BLOCK_FACE_XP: Dir = 3; break;
- default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false;
- }
-
static const struct // Define all the possible painting titles
{
AString Title;
@@ -78,7 +65,7 @@ public:
{ "BurningSkull" }
};
- cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, Dir, a_BlockX, a_BlockY, a_BlockZ);
+ cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_Dir, a_BlockX, a_BlockY, a_BlockZ);
Painting->Initialize(*a_World);
if (!a_Player->IsGameModeCreative())
diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h
index 398ef6805..798573846 100644
--- a/src/Items/ItemPotion.h
+++ b/src/Items/ItemPotion.h
@@ -39,7 +39,7 @@ public:
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * 7;
- if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity::pkSplashPotion, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0)
+ if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity::pkSplashPotion, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID)
{
return false;
}
diff --git a/src/Items/ItemSlab.h b/src/Items/ItemSlab.h
index 1b68b9d0c..b0b5ce005 100644
--- a/src/Items/ItemSlab.h
+++ b/src/Items/ItemSlab.h
@@ -44,8 +44,8 @@ public:
NIBBLETYPE ClickedBlockMeta;
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlockType, ClickedBlockMeta);
if (
- (ClickedBlockType == m_ItemType) && // Placing the same slab material
- (ClickedBlockMeta == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single)
+ (ClickedBlockType == m_ItemType) && // Placing the same slab material
+ ((ClickedBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single)
)
{
// If clicking the top side of a bottom-half slab, combine into a doubleslab:
diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h
index dee8a9057..a07e4ef49 100644
--- a/src/Items/ItemSpawnEgg.h
+++ b/src/Items/ItemSpawnEgg.h
@@ -36,7 +36,7 @@ public:
eMonsterType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage);
if (
(MonsterType != mtInvalidType) && // Valid monster type
- (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded
+ (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) != cEntity::INVALID_ID)) // Spawning succeeded
{
if (!a_Player->IsGameModeCreative())
{
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index c151c5d3a..cdcbdab3b 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -35,7 +35,7 @@ public:
cFastRandom Random;
a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f));
- if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0)
+ if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID)
{
return false;
}
@@ -135,7 +135,7 @@ public:
return false;
}
- if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0)
+ if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0)
{
return false;
}
diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h
index d300184b1..c419aa75a 100644
--- a/src/LoggerListeners.h
+++ b/src/LoggerListeners.h
@@ -1,5 +1,6 @@
#include "Logger.h"
+#include "OSSupport/File.h"
diff --git a/src/Map.cpp b/src/Map.cpp
index fbde00cf7..5e57cc8ec 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -66,10 +66,8 @@ void cMapDecorator::Update(void)
{
cFastRandom Random;
- Int64 WorldAge = m_Player->GetWorld()->GetWorldAge();
-
// TODO 2014-02-19 xdot: Refine
- m_Rot = Random.NextInt(16, (int) WorldAge);
+ m_Rot = Random.NextInt(16);
}
else
{
diff --git a/src/Map.h b/src/Map.h
index fe324a5e7..3e775231a 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -189,6 +189,11 @@ public:
return "cMap";
}
+ const char * GetClass(void) // Needed for ManualBindings' DoWith templates
+ {
+ return "cMap";
+ }
+
protected:
diff --git a/src/MapManager.cpp b/src/MapManager.cpp
index 2a3ab192b..fc67bd901 100644
--- a/src/MapManager.cpp
+++ b/src/MapManager.cpp
@@ -22,7 +22,7 @@ cMapManager::cMapManager(cWorld * a_World)
-bool cMapManager::DoWithMap(int a_ID, cMapCallback & a_Callback)
+bool cMapManager::DoWithMap(UInt32 a_ID, cMapCallback & a_Callback)
{
cCSLock Lock(m_CS);
cMap * Map = GetMapData(a_ID);
diff --git a/src/MapManager.h b/src/MapManager.h
index 2cc6a7bce..1059773c3 100644
--- a/src/MapManager.h
+++ b/src/MapManager.h
@@ -32,8 +32,7 @@ public:
cMapManager(cWorld * a_World);
/** Returns the map with the specified ID, nullptr if out of range.
- WARNING: The returned map object is not thread safe.
- */
+ WARNING: The returned map object is not thread safe. */
cMap * GetMapData(unsigned int a_ID);
/** Creates a new map. Returns nullptr on error */
@@ -41,13 +40,11 @@ public:
/** Calls the callback for the map with the specified ID.
Returns true if the map was found and the callback called, false if map not found.
- Callback return value is ignored.
- */
- bool DoWithMap(int a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp
+ Callback return value is ignored. */
+ bool DoWithMap(UInt32 a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each map.
- Returns true if all maps processed, false if the callback aborted by returning true.
- */
+ Returns true if all maps processed, false if the callback aborted by returning true. */
bool ForEachMap(cMapCallback & a_Callback);
size_t GetNumMaps(void) const; // tolua_export
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index 541135996..dfeab1461 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -110,8 +110,7 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
if (allowedMobsSize > 0)
{
std::set<eMonsterType>::iterator itr = allowedMobs.begin();
- static int Counter = 0;
- int iRandom = m_Random.NextInt((int)allowedMobsSize, Counter++);
+ int iRandom = m_Random.NextInt((int)allowedMobsSize);
for (int i = 0; i < iRandom; i++)
{
@@ -133,7 +132,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
if (a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock))
{
- if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0))
+ if ((a_RelY >= cChunkDef::Height - 1) || (a_RelY <= 0))
{
return false;
}
@@ -187,7 +186,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) &&
(a_RelY >= 62) &&
- (Random.NextInt(3, a_Biome) != 0)
+ (Random.NextInt(3) != 0)
);
}
@@ -248,7 +247,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) &&
(BlockLight <= 7) &&
- (Random.NextInt(2, a_Biome) == 0)
+ (Random.NextInt(2) == 0)
);
}
@@ -272,7 +271,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(BlockBelow)) &&
- (Random.NextInt(20, a_Biome) == 0)
+ (Random.NextInt(20) == 0)
);
}
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 72317d66b..526b39e39 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -85,7 +85,7 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (ReachedFinalDestination() && !LineOfSight.Trace(GetPosition(), AttackDirection, (int)AttackDirection.Length()))
{
// Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
- Attack(a_Dt / 1000);
+ Attack(a_Dt);
}
}
@@ -95,8 +95,7 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cAggressiveMonster::Attack(std::chrono::milliseconds a_Dt)
{
- m_AttackInterval += a_Dt.count() * m_AttackRate;
-
+ m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate;
if ((m_Target == nullptr) || (m_AttackInterval < 3.0))
{
return;
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index 172ccd071..89eeb3709 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -32,7 +32,7 @@ void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cBlaze::Attack(std::chrono::milliseconds a_Dt)
{
- m_AttackInterval += a_Dt.count() * m_AttackRate;
+ m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate;
if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index c4ae47f2f..41796402f 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -67,30 +67,29 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
}
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
- if ((a_Killer != nullptr) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0))
+ // If the creeper was killed by a skeleton, add a random music disc drop:
+ if (
+ (a_Killer != nullptr) &&
+ a_Killer->IsProjectile() &&
+ ((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID))
{
class cProjectileCreatorCallback : public cEntityCallback
{
public:
- cProjectileCreatorCallback(void)
- {
- }
+ cProjectileCreatorCallback(void) {}
virtual bool Item(cEntity * a_Entity) override
{
- if (a_Entity->IsMob() && ((cMonster *)a_Entity)->GetMobType() == mtSkeleton)
+ if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton))
{
return true;
}
return false;
}
- };
-
- cProjectileCreatorCallback PCC;
- if (GetWorld()->DoWithEntityByID(((cProjectileEntity *)a_Killer)->GetCreatorUniqueID(), PCC))
+ } PCC;
+ if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC))
{
- // 12 music discs. TickRand starts from 0 to 11. Disk IDs start at 2256, so add that. There.
- AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256);
+ AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC));
}
}
}
diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp
index ea0295102..d17047ab7 100644
--- a/src/Mobs/Ghast.cpp
+++ b/src/Mobs/Ghast.cpp
@@ -34,7 +34,7 @@ void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cGhast::Attack(std::chrono::milliseconds a_Dt)
{
- m_AttackInterval += a_Dt.count() * m_AttackRate;
+ m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate;
if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 6e07bfbb6..a86497753 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -135,7 +135,7 @@ void cMonster::TickPathFinding()
{ 0, -1},
} ;
- if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
+ if ((PosY - 1 < 0) || (PosY + 2 >= cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
{
// Too low/high, can't really do anything
FinishPathFinding();
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index e4d1760e0..c0cdec035 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -91,7 +91,7 @@ void cSheep::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
int PosY = POSY_TOINT - 1;
int PosZ = POSZ_TOINT;
- if ((PosY <= 0) || (PosY > cChunkDef::Height))
+ if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{
return;
}
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index dd59d6454..331c8e8ad 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -69,8 +69,7 @@ void cSkeleton::MoveToPosition(const Vector3d & a_Position)
void cSkeleton::Attack(std::chrono::milliseconds a_Dt)
{
- m_AttackInterval += a_Dt.count() * m_AttackRate;
-
+ m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate;
if ((m_Target != nullptr) && (m_AttackInterval > 3.0))
{
// Setting this higher gives us more wiggle room for attackrate
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 81b37ef0e..0d3c9a63e 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -13,6 +13,7 @@ SET (SRCS
HostnameLookup.cpp
IPLookup.cpp
IsThread.cpp
+ NetworkInterfaceEnum.cpp
NetworkSingleton.cpp
Semaphore.cpp
ServerHandleImpl.cpp
diff --git a/src/OSSupport/CriticalSection.h b/src/OSSupport/CriticalSection.h
index 17fcdfc12..d52f049d2 100644
--- a/src/OSSupport/CriticalSection.h
+++ b/src/OSSupport/CriticalSection.h
@@ -10,22 +10,22 @@
class cCriticalSection
{
public:
-
void Lock(void);
void Unlock(void);
// IsLocked/IsLockedByCurrentThread are only used in ASSERT statements, but because of the changes with ASSERT they must always be defined
// The fake versions (in Release) will not effect the program in any way
#ifdef _DEBUG
- cCriticalSection(void);
- bool IsLocked(void);
- bool IsLockedByCurrentThread(void);
+ cCriticalSection(void);
+ bool IsLocked(void);
+ bool IsLockedByCurrentThread(void);
#else
- bool IsLocked(void) { return false; }
- bool IsLockedByCurrentThread(void) { return false; }
+ bool IsLocked(void) { return false; }
+ bool IsLockedByCurrentThread(void) { return false; }
#endif // _DEBUG
private:
+
#ifdef _DEBUG
int m_IsLocked; // Number of times this CS is locked
std::thread::id m_OwningThreadID;
diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h
index 5dd596223..95a935bbe 100644
--- a/src/OSSupport/Network.h
+++ b/src/OSSupport/Network.h
@@ -318,6 +318,9 @@ public:
If a_Port is 0, the OS is free to assign any port number it likes to the endpoint.
Returns the endpoint object that can be interacted with. */
static cUDPEndpointPtr CreateUDPEndpoint(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks);
+
+ /** Returns all local IP addresses for network interfaces currently available. */
+ static AStringVector EnumLocalIPAddresses(void);
};
diff --git a/src/OSSupport/NetworkInterfaceEnum.cpp b/src/OSSupport/NetworkInterfaceEnum.cpp
new file mode 100644
index 000000000..c4af1e93c
--- /dev/null
+++ b/src/OSSupport/NetworkInterfaceEnum.cpp
@@ -0,0 +1,185 @@
+
+// NetworkInterfaceEnum.cpp
+
+// Implements the cNetwork::EnumLocalIPAddresses() interface enumeration function
+
+#include "Globals.h"
+#include "Network.h"
+#include "event2/util.h"
+#ifdef _WIN32
+ #include <IPHlpApi.h>
+ #pragma comment(lib, "IPHLPAPI.lib")
+#else // _WIN32
+ #include <sys/types.h>
+ #include <ifaddrs.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif // else _WIN32
+
+
+
+
+
+#ifdef SELF_TEST
+
+static class cEnumIPAddressTest
+{
+public:
+ cEnumIPAddressTest(void)
+ {
+ printf("Enumerating all IP addresses...\n");
+ auto IPs = cNetwork::EnumLocalIPAddresses();
+ for (auto & ip: IPs)
+ {
+ printf(" %s\n", ip.c_str());
+ }
+ printf("Done.\n");
+ }
+} g_EnumIPAddressTest;
+
+#endif // SELF_TEST
+
+
+
+
+
+#ifdef _WIN32
+
+/** Converts the SOCKET_ADDRESS structure received from the OS into an IP address string. */
+static AString PrintAddress(SOCKET_ADDRESS & a_Addr)
+{
+ char IP[128];
+ switch (a_Addr.lpSockaddr->sa_family)
+ {
+ case AF_INET:
+ {
+ auto sin = reinterpret_cast<const sockaddr_in *>(a_Addr.lpSockaddr);
+ evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin_addr), IP, sizeof(IP));
+ break;
+ }
+ case AF_INET6:
+ {
+ auto sin = reinterpret_cast<const sockaddr_in6 *>(a_Addr.lpSockaddr);
+ evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin6_addr), IP, sizeof(IP));
+ break;
+ }
+ default:
+ {
+ IP[0] = 0;
+ break;
+ }
+ }
+ return IP;
+}
+
+#else // _WIN32
+
+static AString PrintAddress(ifaddrs * InterfaceAddress)
+{
+ switch (InterfaceAddress->ifa_addr->sa_family)
+ {
+ case AF_INET:
+ { // IPv4
+ char AddressBuffer[INET_ADDRSTRLEN];
+ sockaddr_in InternetSocket;
+
+ std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
+ inet_ntop(AF_INET, &InternetSocket.sin_addr, AddressBuffer, INET_ADDRSTRLEN);
+ return AddressBuffer;
+ }
+ case AF_INET6:
+ { // IPv6
+ char AddressBuffer[INET6_ADDRSTRLEN];
+ sockaddr_in6 InternetSocket;
+
+ std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
+ inet_ntop(AF_INET6, &InternetSocket.sin6_addr, AddressBuffer, INET6_ADDRSTRLEN);
+ return AddressBuffer;
+ }
+ default:
+ {
+ LOG("Unknown address family: %i", InterfaceAddress->ifa_addr->sa_family);
+ return "";
+ }
+ }
+}
+
+#endif // else _WIN32
+
+
+
+
+
+AStringVector cNetwork::EnumLocalIPAddresses(void)
+{
+ AStringVector res;
+
+ #ifdef _WIN32
+
+ // Query the OS for all adapters' addresses:
+ char buffer[64 KiB]; // A buffer backing the address list
+ PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer);
+ ULONG outBufLen = sizeof(buffer);
+ DWORD dwRetVal = GetAdaptersAddresses(
+ AF_UNSPEC,
+ GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr,
+ pAddresses, &outBufLen
+ );
+ if (dwRetVal != ERROR_SUCCESS)
+ {
+ LOG("GetAdaptersAddresses() failed: %u", dwRetVal);
+ return res;
+ }
+
+ // Enumerate all active adapters
+ for (auto pCurrAddresses = pAddresses; pCurrAddresses != nullptr; pCurrAddresses = pCurrAddresses->Next)
+ {
+ if (pCurrAddresses->OperStatus != IfOperStatusUp)
+ {
+ // Adapter not active, skip it:
+ continue;
+ }
+
+ // Collect all IP addresses on this adapter:
+ for (auto pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next)
+ {
+ auto Address = PrintAddress(pUnicast->Address);
+ if (!Address.empty())
+ {
+ res.push_back(Address);
+ }
+ } // for pUnicast
+ } // for pCurrAddresses
+
+ #else // _WIN32
+
+ struct ifaddrs * ifAddrStruct = nullptr;
+ getifaddrs(&ifAddrStruct);
+
+ for (auto ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
+ {
+ if (ifa->ifa_addr == nullptr)
+ {
+ continue;
+ }
+
+ auto Address = PrintAddress(ifa);
+ if (!Address.empty())
+ {
+ res.emplace_back(Address);
+ }
+ }
+
+ if (ifAddrStruct != nullptr)
+ {
+ freeifaddrs(ifAddrStruct);
+ }
+
+ #endif // else _WIN32
+
+ return res;
+}
+
+
+
+
diff --git a/src/OSSupport/UDPEndpointImpl.cpp b/src/OSSupport/UDPEndpointImpl.cpp
index ece521ab8..31ca107ce 100644
--- a/src/OSSupport/UDPEndpointImpl.cpp
+++ b/src/OSSupport/UDPEndpointImpl.cpp
@@ -197,6 +197,15 @@ cUDPEndpointImpl::cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_C
+cUDPEndpointImpl::~cUDPEndpointImpl()
+{
+ Close();
+}
+
+
+
+
+
void cUDPEndpointImpl::Close(void)
{
if (m_Port == 0)
diff --git a/src/OSSupport/UDPEndpointImpl.h b/src/OSSupport/UDPEndpointImpl.h
index 75942b0cf..0e28d0b13 100644
--- a/src/OSSupport/UDPEndpointImpl.h
+++ b/src/OSSupport/UDPEndpointImpl.h
@@ -35,6 +35,8 @@ public:
If a_Port is 0, the OS is free to assign any port number it likes to the endpoint. */
cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks);
+ ~cUDPEndpointImpl();
+
// cUDPEndpoint overrides:
virtual void Close(void) override;
virtual bool IsOpen(void) const override;
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index 7c97e67bc..c3a45ca47 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -8,19 +8,23 @@ SET (SRCS
Authenticator.cpp
ChunkDataSerializer.cpp
MojangAPI.cpp
+ Packetizer.cpp
Protocol17x.cpp
Protocol18x.cpp
- ProtocolRecognizer.cpp)
+ ProtocolRecognizer.cpp
+)
SET (HDRS
Authenticator.h
ChunkDataSerializer.h
MojangAPI.h
+ Packetizer.h
Protocol.h
Protocol17x.h
Protocol18x.h
- ProtocolRecognizer.h)
+ ProtocolRecognizer.h
+)
-if(NOT MSVC)
+if (NOT MSVC)
add_library(Protocol ${SRCS} ${HDRS})
endif()
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp
index 5d080656d..60fd5f935 100644
--- a/src/Protocol/ChunkDataSerializer.cpp
+++ b/src/Protocol/ChunkDataSerializer.cpp
@@ -187,11 +187,11 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu
// Create the packet:
cByteBuffer Packet(512 KiB);
- Packet.WriteVarInt(0x21); // Packet id (Chunk Data packet)
- Packet.WriteBEInt(a_ChunkX);
- Packet.WriteBEInt(a_ChunkZ);
- Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
- Packet.WriteBEUShort(0xffff); // We're aways sending the full chunk with no additional data, so the bitmap is 0xffff
+ Packet.WriteVarInt32(0x21); // Packet id (Chunk Data packet)
+ Packet.WriteBEInt32(a_ChunkX);
+ Packet.WriteBEInt32(a_ChunkZ);
+ Packet.WriteBool(true); // "Ground-up continuous", or rather, "biome data present" flag
+ Packet.WriteBEUInt16(0xffff); // We're aways sending the full chunk with no additional data, so the bitmap is 0xffff
// Write the chunk size:
const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
@@ -201,15 +201,15 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu
sizeof(m_BlockSkyLight) + // Block sky light
BiomeDataSize // Biome data
);
- Packet.WriteVarInt(ChunkSize);
+ Packet.WriteVarInt32(ChunkSize);
// Write the block types to the packet:
for (size_t Index = 0; Index < cChunkDef::NumBlocks; Index++)
{
BLOCKTYPE BlockType = m_BlockTypes[Index] & 0xFF;
NIBBLETYPE BlockMeta = m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0x0f;
- Packet.WriteByte((unsigned char)(BlockType << 4) | BlockMeta);
- Packet.WriteByte((unsigned char)(BlockType >> 4));
+ Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType << 4) | BlockMeta);
+ Packet.WriteBEUInt8(static_cast<unsigned char>(BlockType >> 4));
}
// Write the rest:
@@ -234,8 +234,8 @@ void cChunkDataSerializer::Serialize47(AString & a_Data, int a_ChunkX, int a_Chu
else
{
AString PostData;
- Buffer.WriteVarInt((UInt32)Packet.GetUsedSpace() + 1);
- Buffer.WriteVarInt(0);
+ Buffer.WriteVarInt32(static_cast<UInt32>(Packet.GetUsedSpace() + 1));
+ Buffer.WriteVarInt32(0);
Buffer.ReadAll(PostData);
Buffer.CommitRead();
diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp
new file mode 100644
index 000000000..0a84d4678
--- /dev/null
+++ b/src/Protocol/Packetizer.cpp
@@ -0,0 +1,101 @@
+
+// Packetizer.cpp
+
+// Implements the cPacketizer class representing a wrapper for sending a single packet over a protocol.
+
+#include "Globals.h"
+#include "Packetizer.h"
+
+
+
+
+
+/** Converts the hex digit character to its value. */
+static UInt8 HexDigitValue(char a_Character)
+{
+ switch (a_Character)
+ {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': return 10;
+ case 'b': return 11;
+ case 'c': return 12;
+ case 'd': return 13;
+ case 'e': return 14;
+ case 'f': return 15;
+ case 'A': return 10;
+ case 'B': return 11;
+ case 'C': return 12;
+ case 'D': return 13;
+ case 'E': return 14;
+ case 'F': return 15;
+ default:
+ {
+ LOGWARNING("Bad hex digit: %c", a_Character);
+ ASSERT(!"Bad hex digit");
+ return 0;
+ }
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPacketizer:
+
+cPacketizer::~cPacketizer()
+{
+ m_Protocol.SendPacket(*this);
+}
+
+
+
+
+
+void cPacketizer::WriteByteAngle(double a_Angle)
+{
+ WriteBEInt8(static_cast<Int8>(255 * a_Angle / 360));
+}
+
+
+
+
+
+void cPacketizer::WriteFPInt(double a_Value)
+{
+ WriteBEInt32(static_cast<Int32>(a_Value * 32));
+}
+
+
+
+
+
+void cPacketizer::WriteUUID(const AString & a_UUID)
+{
+ if (a_UUID.length() != 32)
+ {
+ LOGWARNING("%s: Attempt to send a bad uuid (length isn't 32): %s", __FUNCTION__, a_UUID.c_str());
+ ASSERT(!"Wrong uuid length!");
+ return;
+ }
+
+ for (size_t i = 0; i < 32; i += 2)
+ {
+ auto val = static_cast<UInt8>(HexDigitValue(a_UUID[i]) << 4 | HexDigitValue(a_UUID[i + 1]));
+ VERIFY(m_Out.WriteBEUInt8(val));
+ }
+}
+
+
+
+
diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h
new file mode 100644
index 000000000..7f5e9c2c3
--- /dev/null
+++ b/src/Protocol/Packetizer.h
@@ -0,0 +1,155 @@
+
+// Packetizer.h
+
+// Declares the cPacketizer class representing a wrapper for sending a single packet over a protocol.
+// The class provides auto-locking, serialization and send-on-instance-destroy semantics
+
+
+
+
+
+#pragma once
+
+#include "Protocol.h"
+#include "../ByteBuffer.h"
+
+
+
+
+
+/** Composes an individual packet in the protocol's m_OutPacketBuffer; sends it just before being destructed. */
+class cPacketizer
+{
+public:
+ /** Starts serializing a new packet into the protocol's m_OutPacketBuffer.
+ Locks the protocol's m_CSPacket to avoid multithreading issues. */
+ cPacketizer(cProtocol & a_Protocol, UInt32 a_PacketType) :
+ m_Protocol(a_Protocol),
+ m_Out(a_Protocol.m_OutPacketBuffer),
+ m_Lock(a_Protocol.m_CSPacket),
+ m_PacketType(a_PacketType) // Used for logging purposes
+ {
+ m_Out.WriteVarInt32(a_PacketType);
+ }
+
+ /** Sends the packet via the contained protocol's SendPacket() function. */
+ ~cPacketizer();
+
+ inline void WriteBool(bool a_Value)
+ {
+ VERIFY(m_Out.WriteBool(a_Value));
+ }
+
+ inline void WriteBEUInt8(UInt8 a_Value)
+ {
+ VERIFY(m_Out.WriteBEUInt8(a_Value));
+ }
+
+
+ inline void WriteBEInt8(Int8 a_Value)
+ {
+ VERIFY(m_Out.WriteBEInt8(a_Value));
+ }
+
+
+ inline void WriteBEInt16(Int16 a_Value)
+ {
+ VERIFY(m_Out.WriteBEInt16(a_Value));
+ }
+
+
+ inline void WriteBEUInt16(short a_Value)
+ {
+ VERIFY(m_Out.WriteBEUInt16(a_Value));
+ }
+
+
+ inline void WriteBEInt32(Int32 a_Value)
+ {
+ VERIFY(m_Out.WriteBEInt32(a_Value));
+ }
+
+
+ inline void WriteBEUInt32(UInt32 a_Value)
+ {
+ VERIFY(m_Out.WriteBEUInt32(a_Value));
+ }
+
+
+ inline void WriteBEInt64(Int64 a_Value)
+ {
+ VERIFY(m_Out.WriteBEInt64(a_Value));
+ }
+
+
+ inline void WriteBEUInt64(UInt64 a_Value)
+ {
+ VERIFY(m_Out.WriteBEUInt64(a_Value));
+ }
+
+
+ inline void WriteBEFloat(float a_Value)
+ {
+ VERIFY(m_Out.WriteBEFloat(a_Value));
+ }
+
+
+ inline void WriteBEDouble(double a_Value)
+ {
+ VERIFY(m_Out.WriteBEDouble(a_Value));
+ }
+
+
+ inline void WriteVarInt32(UInt32 a_Value)
+ {
+ VERIFY(m_Out.WriteVarInt32(a_Value));
+ }
+
+
+ inline void WriteString(const AString & a_Value)
+ {
+ VERIFY(m_Out.WriteVarUTF8String(a_Value));
+ }
+
+
+ inline void WriteBuf(const char * a_Data, size_t a_Size)
+ {
+ VERIFY(m_Out.Write(a_Data, a_Size));
+ }
+
+
+ /** Writes the specified block position as a single encoded 64-bit BigEndian integer. */
+ inline void WritePosition64(int a_BlockX, int a_BlockY, int a_BlockZ)
+ {
+ VERIFY(m_Out.WritePosition64(a_BlockX, a_BlockY, a_BlockZ));
+ }
+
+ /** Writes the specified angle using a single byte. */
+ void WriteByteAngle(double a_Angle);
+
+ /** Writes the double value as a 27:5 fixed-point integer. */
+ void WriteFPInt(double a_Value);
+
+ /** Writes the specified UUID as a 128-bit BigEndian integer. */
+ void WriteUUID(const AString & a_UUID);
+
+ UInt32 GetPacketType(void) const { return m_PacketType; }
+
+protected:
+ /** The protocol instance in which the packet is being constructed. */
+ cProtocol & m_Protocol;
+
+ /** The protocol's buffer for the constructed packet data. */
+ cByteBuffer & m_Out;
+
+ /** The RAII lock preventing multithreaded access to the protocol buffer while constructing the packet. */
+ cCSLock m_Lock;
+
+ /** Type of the contained packet.
+ Used for logging purposes, the packet type is encoded into m_Out immediately in constructor. */
+ UInt32 m_PacketType;
+} ;
+
+
+
+
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 02a8a52f6..d8399049e 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -14,6 +14,7 @@
#include "../Endianness.h"
#include "../Scoreboard.h"
#include "../Map.h"
+#include "../ByteBuffer.h"
@@ -32,6 +33,7 @@ class cChunkDataSerializer;
class cFallingBlock;
class cCompositeChat;
class cStatManager;
+class cPacketizer;
@@ -47,7 +49,9 @@ class cProtocol
{
public:
cProtocol(cClientHandle * a_Client) :
- m_Client(a_Client)
+ m_Client(a_Client),
+ m_OutPacketBuffer(64 KiB),
+ m_OutPacketLenBuffer(20) // 20 bytes is more than enough for one VarInt
{
}
@@ -59,7 +63,7 @@ public:
// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0;
- virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0;
+ virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0;
virtual void SendChat (const AString & a_Message) = 0;
@@ -136,11 +140,27 @@ public:
virtual AString GetAuthServerID(void) = 0;
protected:
+ friend class cPacketizer;
+
cClientHandle * m_Client;
- cCriticalSection m_CSPacket; // Each SendXYZ() function must acquire this CS in order to send the whole packet at once
- /// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it
+ /** Provides synchronization for sending the entire packet at once.
+ Each SendXYZ() function must acquire this CS in order to send the whole packet at once.
+ Automated via cPacketizer class. */
+ cCriticalSection m_CSPacket;
+
+ /** Buffer for composing the outgoing packets, through cPacketizer */
+ cByteBuffer m_OutPacketBuffer;
+
+ /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */
+ cByteBuffer m_OutPacketLenBuffer;
+
+ /** A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it. */
virtual void SendData(const char * a_Data, size_t a_Size) = 0;
+
+ /** Sends a single packet contained within the cPacketizer class.
+ The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */
+ virtual void SendPacket(cPacketizer & a_Packet) = 0;
} ;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index f78c2e54b..2bc58e7e5 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -14,6 +14,7 @@ Implements the 1.7.x protocol classes:
#include "Protocol17x.h"
#include "ChunkDataSerializer.h"
#include "PolarSSL++/Sha1Checksum.h"
+#include "Packetizer.h"
#include "../ClientHandle.h"
#include "../Root.h"
@@ -50,6 +51,13 @@ Implements the 1.7.x protocol classes:
+/** The slot number that the client uses to indicate "outside the window". */
+static const Int16 SLOT_NUM_OUTSIDE = -999;
+
+
+
+
+
#define HANDLE_READ(ByteBuf, Proc, Type, Var) \
Type Var; \
if (!ByteBuf.Proc(Var))\
@@ -98,8 +106,6 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
m_ServerPort(a_ServerPort),
m_State(a_State),
m_ReceivedData(32 KiB),
- m_OutPacketBuffer(64 KiB),
- m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt
m_IsEncrypted(false),
m_LastSentDimension(dimNotSet)
{
@@ -159,8 +165,8 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0);
Pkt.WriteBool(false);
}
@@ -173,28 +179,28 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x24); // Block Action packet
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteShort(static_cast<short>(a_BlockY));
- Pkt.WriteInt(a_BlockZ);
- Pkt.WriteByte(static_cast<Byte>(a_Byte1));
- Pkt.WriteByte(static_cast<Byte>(a_Byte2));
- Pkt.WriteVarInt(a_BlockType);
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEInt16(static_cast<Int16>(a_BlockY));
+ Pkt.WriteBEInt32(a_BlockZ);
+ Pkt.WriteBEInt8(a_Byte1);
+ Pkt.WriteBEInt8(a_Byte2);
+ Pkt.WriteVarInt32(a_BlockType);
}
-void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
+void cProtocol172::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_EntityID));
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteInt(a_BlockY);
- Pkt.WriteInt(a_BlockZ);
- Pkt.WriteChar(a_Stage);
+ Pkt.WriteVarInt32(a_EntityID);
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEInt32(a_BlockY);
+ Pkt.WriteBEInt32(a_BlockZ);
+ Pkt.WriteBEInt8(a_Stage);
}
@@ -207,11 +213,11 @@ void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
ASSERT((a_BlockY >= 0) && (a_BlockY < 256));
cPacketizer Pkt(*this, 0x23); // Block Change packet
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteByte(static_cast<Byte>(a_BlockY));
- Pkt.WriteInt(a_BlockZ);
- Pkt.WriteVarInt(a_BlockType);
- Pkt.WriteByte(a_BlockMeta);
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEUInt8(static_cast<UInt8>(a_BlockY));
+ Pkt.WriteBEInt32(a_BlockZ);
+ Pkt.WriteVarInt32(a_BlockType);
+ Pkt.WriteBEUInt8(a_BlockMeta);
}
@@ -223,15 +229,15 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
- Pkt.WriteInt(a_ChunkX);
- Pkt.WriteInt(a_ChunkZ);
- Pkt.WriteShort((short)a_Changes.size());
- Pkt.WriteInt((int)a_Changes.size() * 4);
+ Pkt.WriteBEInt32(a_ChunkX);
+ Pkt.WriteBEInt32(a_ChunkZ);
+ Pkt.WriteBEUInt16(static_cast<UInt16>(a_Changes.size()));
+ Pkt.WriteBEUInt32(static_cast<UInt32>(a_Changes.size() * 4));
for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
{
int Coords = itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12);
int Blocks = static_cast<int>(itr->m_BlockMeta | (itr->m_BlockType << 4));
- Pkt.WriteInt((Coords << 16) | Blocks);
+ Pkt.WriteBEInt32((Coords << 16) | Blocks);
} // for itr - a_Changes[]
}
@@ -276,8 +282,8 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2, a_ChunkX, a_ChunkZ);
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
- Pkt.WriteInt(a_ChunkX);
- Pkt.WriteInt(a_ChunkZ);
+ Pkt.WriteBEInt32(a_ChunkX);
+ Pkt.WriteBEInt32(a_ChunkZ);
Pkt.WriteBuf(ChunkData.data(), ChunkData.size());
}
@@ -290,8 +296,8 @@ void cProtocol172::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0d); // Collect Item packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteInt(a_Player.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Player.GetUniqueID());
}
@@ -303,8 +309,8 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
- Pkt.WriteByte(1);
- Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(1);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
}
@@ -341,9 +347,9 @@ void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteInt(a_BlockY);
- Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEInt32(a_BlockY);
+ Pkt.WriteBEInt32(a_BlockZ);
}
@@ -357,10 +363,10 @@ void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in
ASSERT((a_Amplifier >= 0) && (a_Amplifier < 256));
cPacketizer Pkt(*this, 0x1D); // Entity Effect packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(static_cast<Byte>(a_EffectID));
- Pkt.WriteByte(static_cast<Byte>(a_Amplifier));
- Pkt.WriteShort(a_Duration);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_EffectID));
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Amplifier));
+ Pkt.WriteBEInt16(a_Duration);
}
@@ -372,9 +378,9 @@ void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteShort(a_SlotNum);
- Pkt.WriteItem(a_Item);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt16(a_SlotNum);
+ WriteItem(Pkt, a_Item);
}
@@ -386,7 +392,7 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
}
@@ -399,7 +405,7 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x16); // Entity Look packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetYaw());
Pkt.WriteByteAngle(a_Entity.GetPitch());
}
@@ -413,9 +419,9 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteEntityMetadata(a_Entity);
- Pkt.WriteByte(0x7f); // The termination byte
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ WriteEntityMetadata(Pkt, a_Entity);
+ Pkt.WriteBEUInt8(0x7f); // The termination byte
}
@@ -427,8 +433,8 @@ void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x20); // Entity Properties packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteEntityProperties(a_Entity);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ WriteEntityProperties(Pkt, a_Entity);
}
@@ -440,10 +446,10 @@ void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteChar(a_RelX);
- Pkt.WriteChar(a_RelY);
- Pkt.WriteChar(a_RelZ);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_RelX);
+ Pkt.WriteBEInt8(a_RelY);
+ Pkt.WriteBEInt8(a_RelZ);
}
@@ -455,10 +461,10 @@ void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteChar(a_RelX);
- Pkt.WriteChar(a_RelY);
- Pkt.WriteChar(a_RelZ);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_RelX);
+ Pkt.WriteBEInt8(a_RelY);
+ Pkt.WriteBEInt8(a_RelZ);
Pkt.WriteByteAngle(a_Entity.GetYaw());
Pkt.WriteByteAngle(a_Entity.GetPitch());
}
@@ -472,8 +478,8 @@ void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1a); // Entity Status packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteChar(a_Status);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_Status);
}
@@ -485,11 +491,11 @@ void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
- Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedZ() * 400));
}
@@ -501,20 +507,20 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x27); // Explosion packet
- Pkt.WriteFloat((float)a_BlockX);
- Pkt.WriteFloat((float)a_BlockY);
- Pkt.WriteFloat((float)a_BlockZ);
- Pkt.WriteFloat((float)a_Radius);
- Pkt.WriteInt((int)a_BlocksAffected.size());
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockX));
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockY));
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockZ));
+ Pkt.WriteBEFloat(static_cast<float>(a_Radius));
+ Pkt.WriteBEUInt32(static_cast<UInt32>(a_BlocksAffected.size()));
for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr)
{
- Pkt.WriteChar((char)itr->x);
- Pkt.WriteChar((char)itr->y);
- Pkt.WriteChar((char)itr->z);
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->x));
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->y));
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->z));
} // for itr - a_BlockAffected[]
- Pkt.WriteFloat((float)a_PlayerMotion.x);
- Pkt.WriteFloat((float)a_PlayerMotion.y);
- Pkt.WriteFloat((float)a_PlayerMotion.z);
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.x));
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.y));
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.z));
}
@@ -526,8 +532,8 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
- Pkt.WriteByte(3); // Reason: Change game mode
- Pkt.WriteFloat((float)a_GameMode);
+ Pkt.WriteBEUInt8(3); // Reason: Change game mode
+ Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float!
}
@@ -540,9 +546,9 @@ void cProtocol172::SendHealth(void)
cPacketizer Pkt(*this, 0x06); // Update Health packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteFloat(static_cast<float>(Player->GetHealth()));
- Pkt.WriteShort(static_cast<short>(Player->GetFoodLevel()));
- Pkt.WriteFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth()));
+ Pkt.WriteBEInt16(static_cast<short>(Player->GetFoodLevel()));
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
}
@@ -554,9 +560,9 @@ void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2f); // Set Slot packet
- Pkt.WriteChar(a_WindowID);
- Pkt.WriteShort(a_SlotNum);
- Pkt.WriteItem(a_Item);
+ Pkt.WriteBEInt8(a_WindowID);
+ Pkt.WriteBEInt16(a_SlotNum);
+ WriteItem(Pkt, a_Item);
}
@@ -573,7 +579,7 @@ void cProtocol172::SendKeepAlive(int a_PingID)
}
cPacketizer Pkt(*this, 0x00); // Keep Alive packet
- Pkt.WriteInt(a_PingID);
+ Pkt.WriteBEInt32(a_PingID);
}
@@ -586,11 +592,11 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
cServer * Server = cRoot::Get()->GetServer();
cPacketizer Pkt(*this, 0x01); // Join Game packet
- Pkt.WriteInt(a_Player.GetUniqueID());
- Pkt.WriteByte(static_cast<Byte>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
- Pkt.WriteChar(static_cast<char>(a_World.GetDimension()));
- Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
- Pkt.WriteByte(static_cast<Byte>(std::min(Server->GetMaxPlayers(), 60)));
+ Pkt.WriteBEUInt32(a_Player.GetUniqueID());
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
+ Pkt.WriteBEInt8(static_cast<char>(a_World.GetDimension()));
+ Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteBEUInt8(static_cast<Byte>(std::min(Server->GetMaxPlayers(), 60)));
Pkt.WriteString("default"); // Level type - wtf?
}
m_LastSentDimension = a_World.GetDimension();
@@ -598,9 +604,9 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
// Send the spawn position:
{
cPacketizer Pkt(*this, 0x05); // Spawn Position packet
- Pkt.WriteInt(static_cast<int>(a_World.GetSpawnX()));
- Pkt.WriteInt(static_cast<int>(a_World.GetSpawnY()));
- Pkt.WriteInt(static_cast<int>(a_World.GetSpawnZ()));
+ Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnX()));
+ Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnY()));
+ Pkt.WriteBEInt32(static_cast<int>(a_World.GetSpawnZ()));
}
// Send player abilities:
@@ -632,19 +638,19 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Painting.GetUniqueID()));
+ Pkt.WriteVarInt32(a_Painting.GetUniqueID());
Pkt.WriteString(a_Painting.GetName().c_str());
- Pkt.WriteInt(static_cast<int>(a_Painting.GetPosX()));
- Pkt.WriteInt(static_cast<int>(a_Painting.GetPosY()));
- Pkt.WriteInt(static_cast<int>(a_Painting.GetPosZ()));
- Pkt.WriteInt(a_Painting.GetDirection());
+ Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosX()));
+ Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosY()));
+ Pkt.WriteBEInt32(static_cast<int>(a_Painting.GetPosZ()));
+ Pkt.WriteBEInt32(a_Painting.GetProtocolFacing());
}
-void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale)
+void cProtocol172::SendMapColumn(int a_MapID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale)
{
ASSERT(m_State == 3); // In game mode?
ASSERT(a_Length + 3 <= USHRT_MAX);
@@ -652,12 +658,12 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo
ASSERT((a_Y >= 0) && (a_Y < 256));
cPacketizer Pkt(*this, 0x34);
- Pkt.WriteVarInt(static_cast<UInt32>(a_ID));
- Pkt.WriteShort (static_cast<short>(3 + a_Length));
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID));
+ Pkt.WriteBEUInt16(static_cast<UInt16>(3 + a_Length));
- Pkt.WriteByte(0);
- Pkt.WriteByte(static_cast<Byte>(a_X));
- Pkt.WriteByte(static_cast<Byte>(a_Y));
+ Pkt.WriteBEUInt8(0);
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_X));
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Y));
Pkt.WriteBuf(reinterpret_cast<const char *>(a_Colors), a_Length);
}
@@ -666,24 +672,24 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo
-void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale)
+void cProtocol172::SendMapDecorators(int a_MapID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale)
{
ASSERT(m_State == 3); // In game mode?
ASSERT(1 + 3 * a_Decorators.size() < USHRT_MAX);
cPacketizer Pkt(*this, 0x34);
- Pkt.WriteVarInt(static_cast<UInt32>(a_ID));
- Pkt.WriteShort (static_cast<short>(1 + (3 * a_Decorators.size())));
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID));
+ Pkt.WriteBEUInt16(static_cast<UInt16>(1 + (3 * a_Decorators.size())));
- Pkt.WriteByte(1);
+ Pkt.WriteBEUInt8(1);
for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it)
{
ASSERT(it->GetPixelX() < 256);
ASSERT(it->GetPixelZ() < 256);
- Pkt.WriteByte(static_cast<Byte>((it->GetType() << 4) | static_cast<Byte>(it->GetRot() & 0xf)));
- Pkt.WriteByte(static_cast<Byte>(it->GetPixelX()));
- Pkt.WriteByte(static_cast<Byte>(it->GetPixelZ()));
+ Pkt.WriteBEUInt8(static_cast<Byte>((it->GetType() << 4) | static_cast<Byte>(it->GetRot() & 0xf)));
+ Pkt.WriteBEUInt8(static_cast<Byte>(it->GetPixelX()));
+ Pkt.WriteBEUInt8(static_cast<Byte>(it->GetPixelZ()));
}
}
@@ -691,17 +697,17 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
-void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
+void cProtocol172::SendMapInfo(int a_MapID, unsigned int a_Scale)
{
ASSERT(m_State == 3); // In game mode?
ASSERT(a_Scale < 256);
cPacketizer Pkt(*this, 0x34);
- Pkt.WriteVarInt(static_cast<UInt32>(a_ID));
- Pkt.WriteShort (2);
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_MapID));
+ Pkt.WriteBEUInt16(2);
- Pkt.WriteByte(2);
- Pkt.WriteByte(static_cast<Byte>(a_Scale));
+ Pkt.WriteBEUInt8(2);
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Scale));
}
@@ -714,21 +720,21 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
{
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Pickup.GetUniqueID()));
- Pkt.WriteByte(2); // Type = Pickup
+ Pkt.WriteVarInt32(a_Pickup.GetUniqueID());
+ Pkt.WriteBEUInt8(2); // Type = Pickup
Pkt.WriteFPInt(a_Pickup.GetPosX());
Pkt.WriteFPInt(a_Pickup.GetPosY());
Pkt.WriteFPInt(a_Pickup.GetPosZ());
Pkt.WriteByteAngle(a_Pickup.GetYaw());
Pkt.WriteByteAngle(a_Pickup.GetPitch());
- Pkt.WriteInt(0); // No object data
+ Pkt.WriteBEInt32(0); // No object data
}
{
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
- Pkt.WriteInt(a_Pickup.GetUniqueID());
- Pkt.WriteByte((0x05 << 5) | 10); // Slot type + index 10
- Pkt.WriteItem(a_Pickup.GetItem());
- Pkt.WriteByte(0x7f); // End of metadata
+ Pkt.WriteBEUInt32(a_Pickup.GetUniqueID());
+ Pkt.WriteBEUInt8((0x05 << 5) | 10); // Slot type + index 10
+ WriteItem(Pkt, a_Pickup.GetItem());
+ Pkt.WriteBEUInt8(0x7f); // End of metadata
}
}
@@ -756,9 +762,9 @@ void cProtocol172::SendPlayerAbilities(void)
{
Flags |= 0x04;
}
- Pkt.WriteByte(Flags);
- Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed()));
- Pkt.WriteFloat((float)(0.1 * Player->GetNormalMaxSpeed()));
+ Pkt.WriteBEUInt8(Flags);
+ Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed()));
+ Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed()));
}
@@ -770,8 +776,8 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0b); // Animation packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Entity.GetUniqueID()));
- Pkt.WriteChar(a_Animation);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_Animation);
}
@@ -784,14 +790,14 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr
cPacketizer Pkt(*this, 0x2A);
Pkt.WriteString(a_ParticleName);
- Pkt.WriteFloat(a_SrcX);
- Pkt.WriteFloat(a_SrcY);
- Pkt.WriteFloat(a_SrcZ);
- Pkt.WriteFloat(a_OffsetX);
- Pkt.WriteFloat(a_OffsetY);
- Pkt.WriteFloat(a_OffsetZ);
- Pkt.WriteFloat(a_ParticleData);
- Pkt.WriteInt(a_ParticleAmount);
+ Pkt.WriteBEFloat(a_SrcX);
+ Pkt.WriteBEFloat(a_SrcY);
+ Pkt.WriteBEFloat(a_SrcZ);
+ Pkt.WriteBEFloat(a_OffsetX);
+ Pkt.WriteBEFloat(a_OffsetY);
+ Pkt.WriteBEFloat(a_OffsetZ);
+ Pkt.WriteBEFloat(a_ParticleData);
+ Pkt.WriteBEInt32(a_ParticleAmount);
}
@@ -805,7 +811,7 @@ void cProtocol172::SendPlayerListAddPlayer(const cPlayer & a_Player)
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(true);
- Pkt.WriteShort(a_Player.GetClientHandle()->GetPing());
+ Pkt.WriteBEInt16(a_Player.GetClientHandle()->GetPing());
}
@@ -819,7 +825,7 @@ void cProtocol172::SendPlayerListRemovePlayer(const cPlayer & a_Player)
cPacketizer Pkt(*this, 0x38);
Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(false);
- Pkt.WriteShort(0);
+ Pkt.WriteBEInt16(0);
}
@@ -863,22 +869,22 @@ void cProtocol172::SendPlayerMaxSpeed(void)
cPacketizer Pkt(*this, 0x20); // Entity Properties
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteInt(Player->GetUniqueID());
- Pkt.WriteInt(1); // Count
+ Pkt.WriteBEUInt32(Player->GetUniqueID());
+ Pkt.WriteBEInt32(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
- Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed());
+ Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
- Pkt.WriteShort(1); // Modifier count
- Pkt.WriteInt64(0x662a6b8dda3e4c1c);
- Pkt.WriteInt64(static_cast<Int64>(0x881396ea6097278d)); // UUID of the modifier
- Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
- Pkt.WriteByte(2);
+ Pkt.WriteBEInt16(1); // Modifier count
+ Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
+ Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
+ Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
+ Pkt.WriteBEUInt8(2);
}
else
{
- Pkt.WriteShort(0); // Modifier count
+ Pkt.WriteBEInt16(0); // Modifier count
}
}
@@ -892,15 +898,15 @@ void cProtocol172::SendPlayerMoveLook(void)
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteDouble(Player->GetPosX());
+ Pkt.WriteBEDouble(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(Player->GetStance() + 0.001);
+ Pkt.WriteBEDouble(Player->GetStance() + 0.001);
- Pkt.WriteDouble(Player->GetPosZ());
- Pkt.WriteFloat((float)Player->GetYaw());
- Pkt.WriteFloat((float)Player->GetPitch());
+ Pkt.WriteBEDouble(Player->GetPosZ());
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw()));
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch()));
Pkt.WriteBool(Player->IsOnGround());
}
@@ -924,7 +930,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
- Pkt.WriteVarInt((UInt32) a_Player.GetUniqueID());
+ Pkt.WriteVarInt32(a_Player.GetUniqueID());
Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID()));
if (a_Player.HasCustomName())
{
@@ -940,10 +946,10 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
Pkt.WriteByteAngle(a_Player.GetYaw());
Pkt.WriteByteAngle(a_Player.GetPitch());
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
- Pkt.WriteShort(ItemType);
- Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
- Pkt.WriteFloat((float)a_Player.GetHealth());
- Pkt.WriteByte(0x7f); // Metadata: end
+ Pkt.WriteBEInt16(ItemType);
+ Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6
+ Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth()));
+ Pkt.WriteBEUInt8(0x7f); // Metadata: end
}
@@ -953,10 +959,11 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
{
ASSERT(m_State == 3); // In game mode?
+ ASSERT(a_Message.size() <= std::numeric_limits<UInt16>::max());
cPacketizer Pkt(*this, 0x3f);
Pkt.WriteString(a_Channel);
- Pkt.WriteShort((short)a_Message.size());
+ Pkt.WriteBEUInt16(static_cast<UInt16>(a_Message.size()));
Pkt.WriteBuf(a_Message.data(), a_Message.size());
}
@@ -970,8 +977,8 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
ASSERT((a_EffectID >= 0) && (a_EffectID < 256));
cPacketizer Pkt(*this, 0x1e);
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(static_cast<Byte>(a_EffectID));
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_EffectID));
}
@@ -988,9 +995,9 @@ void cProtocol172::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimens
cPacketizer Pkt(*this, 0x07); // Respawn packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteInt((int)a_Dimension);
- Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
- Pkt.WriteByte((Byte)Player->GetEffectiveGameMode());
+ Pkt.WriteBEInt32((int)a_Dimension);
+ Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteBEUInt8((Byte)Player->GetEffectiveGameMode());
Pkt.WriteString("default");
m_LastSentDimension = a_Dimension;
}
@@ -1005,9 +1012,9 @@ void cProtocol172::SendExperience (void)
cPacketizer Pkt(*this, 0x1f); // Experience Packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteFloat(Player->GetXpPercentage());
- Pkt.WriteShort(Player->GetXpLevel());
- Pkt.WriteShort(Player->GetCurrentXp());
+ Pkt.WriteBEFloat(Player->GetXpPercentage());
+ Pkt.WriteBEInt16(static_cast<UInt16>(std::max<int>(Player->GetXpLevel(), std::numeric_limits<UInt16>::max())));
+ Pkt.WriteBEInt16(static_cast<UInt16>(std::max<int>(Player->GetCurrentXp(), std::numeric_limits<UInt16>::max())));
}
@@ -1020,11 +1027,11 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
ASSERT((a_ExpOrb.GetReward() >= 0) && (a_ExpOrb.GetReward() < SHRT_MAX));
cPacketizer Pkt(*this, 0x11);
- Pkt.WriteVarInt(static_cast<UInt32>(a_ExpOrb.GetUniqueID()));
+ Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID());
Pkt.WriteFPInt(a_ExpOrb.GetPosX());
Pkt.WriteFPInt(a_ExpOrb.GetPosY());
Pkt.WriteFPInt(a_ExpOrb.GetPosZ());
- Pkt.WriteShort(static_cast<short>(a_ExpOrb.GetReward()));
+ Pkt.WriteBEInt16(static_cast<short>(a_ExpOrb.GetReward()));
}
@@ -1038,7 +1045,7 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString
cPacketizer Pkt(*this, 0x3b);
Pkt.WriteString(a_Name);
Pkt.WriteString(a_DisplayName);
- Pkt.WriteByte(a_Mode);
+ Pkt.WriteBEUInt8(a_Mode);
}
@@ -1051,12 +1058,12 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString &
cPacketizer Pkt(*this, 0x3c);
Pkt.WriteString(a_Player);
- Pkt.WriteByte(a_Mode);
+ Pkt.WriteBEUInt8(a_Mode);
if (a_Mode != 1)
{
Pkt.WriteString(a_Objective);
- Pkt.WriteInt((int) a_Score);
+ Pkt.WriteBEInt32((int) a_Score);
}
}
@@ -1069,7 +1076,7 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3d);
- Pkt.WriteByte(static_cast<Byte>(a_Display));
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Display));
Pkt.WriteString(a_Objective);
}
@@ -1083,11 +1090,11 @@ void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, doub
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName);
- Pkt.WriteInt(static_cast<int>(a_X * 8.0));
- Pkt.WriteInt(static_cast<int>(a_Y * 8.0));
- Pkt.WriteInt(static_cast<int>(a_Z * 8.0));
- Pkt.WriteFloat(a_Volume);
- Pkt.WriteByte(static_cast<Byte>(a_Pitch * 63));
+ Pkt.WriteBEInt32(static_cast<int>(a_X * 8.0));
+ Pkt.WriteBEInt32(static_cast<int>(a_Y * 8.0));
+ Pkt.WriteBEInt32(static_cast<int>(a_Z * 8.0));
+ Pkt.WriteBEFloat(a_Volume);
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_Pitch * 63));
}
@@ -1100,11 +1107,11 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
ASSERT((a_SrcY >= 0) && (a_SrcY < 256));
cPacketizer Pkt(*this, 0x28); // Effect packet
- Pkt.WriteInt(a_EffectID);
- Pkt.WriteInt(a_SrcX);
- Pkt.WriteByte(static_cast<Byte>(a_SrcY));
- Pkt.WriteInt(a_SrcZ);
- Pkt.WriteInt(a_Data);
+ Pkt.WriteBEInt32(a_EffectID);
+ Pkt.WriteBEInt32(a_SrcX);
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_SrcY));
+ Pkt.WriteBEInt32(a_SrcZ);
+ Pkt.WriteBEInt32(a_Data);
Pkt.WriteBool(false);
}
@@ -1117,17 +1124,17 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_FallingBlock.GetUniqueID()));
- Pkt.WriteByte(70); // Falling block
+ Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID());
+ Pkt.WriteBEUInt8(70); // Falling block
Pkt.WriteFPInt(a_FallingBlock.GetPosX());
Pkt.WriteFPInt(a_FallingBlock.GetPosY());
Pkt.WriteFPInt(a_FallingBlock.GetPosZ());
Pkt.WriteByteAngle(a_FallingBlock.GetYaw());
Pkt.WriteByteAngle(a_FallingBlock.GetPitch());
- Pkt.WriteInt((static_cast<int>(a_FallingBlock.GetBlockType()) | ((static_cast<int>(a_FallingBlock.GetBlockMeta()) << 16))));
- Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedX() * 400));
- Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedY() * 400));
- Pkt.WriteShort(static_cast<short>(a_FallingBlock.GetSpeedZ() * 400));
+ Pkt.WriteBEInt32((static_cast<int>(a_FallingBlock.GetBlockType()) | ((static_cast<int>(a_FallingBlock.GetBlockMeta()) << 16))));
+ Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedX() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedY() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_FallingBlock.GetSpeedZ() * 400));
}
@@ -1139,19 +1146,19 @@ void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Mob.GetUniqueID()));
- Pkt.WriteByte((Byte)a_Mob.GetMobType());
+ Pkt.WriteVarInt32(a_Mob.GetUniqueID());
+ Pkt.WriteBEUInt8((Byte)a_Mob.GetMobType());
Pkt.WriteFPInt(a_Mob.GetPosX());
Pkt.WriteFPInt(a_Mob.GetPosY());
Pkt.WriteFPInt(a_Mob.GetPosZ());
Pkt.WriteByteAngle(a_Mob.GetPitch());
Pkt.WriteByteAngle(a_Mob.GetHeadYaw());
Pkt.WriteByteAngle(a_Mob.GetYaw());
- Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedX() * 400));
- Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedY() * 400));
- Pkt.WriteShort(static_cast<short>(a_Mob.GetSpeedZ() * 400));
- Pkt.WriteEntityMetadata(a_Mob);
- Pkt.WriteByte(0x7f); // Metadata terminator
+ Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedX() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedY() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Mob.GetSpeedZ() * 400));
+ WriteEntityMetadata(Pkt, a_Mob);
+ Pkt.WriteBEUInt8(0x7f); // Metadata terminator
}
@@ -1163,19 +1170,19 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Entity.GetUniqueID()));
- Pkt.WriteChar(a_ObjectType);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_ObjectType);
Pkt.WriteFPInt(a_Entity.GetPosX());
Pkt.WriteFPInt(a_Entity.GetPosY());
Pkt.WriteFPInt(a_Entity.GetPosZ());
Pkt.WriteByteAngle(a_Entity.GetPitch());
Pkt.WriteByteAngle(a_Entity.GetYaw());
- Pkt.WriteInt(a_ObjectData);
+ Pkt.WriteBEInt32(a_ObjectData);
if (a_ObjectData != 0)
{
- Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedX() * 400));
- Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedY() * 400));
- Pkt.WriteShort(static_cast<short>(a_Entity.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteBEInt16(static_cast<short>(a_Entity.GetSpeedZ() * 400));
}
}
@@ -1188,19 +1195,19 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Vehicle.GetUniqueID()));
- Pkt.WriteChar(a_VehicleType);
+ Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
+ Pkt.WriteBEInt8(a_VehicleType);
Pkt.WriteFPInt(a_Vehicle.GetPosX());
Pkt.WriteFPInt(a_Vehicle.GetPosY());
Pkt.WriteFPInt(a_Vehicle.GetPosZ());
Pkt.WriteByteAngle(a_Vehicle.GetPitch());
Pkt.WriteByteAngle(a_Vehicle.GetYaw());
- Pkt.WriteInt(a_VehicleSubType);
+ Pkt.WriteBEInt32(a_VehicleSubType);
if (a_VehicleSubType != 0)
{
- Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedX() * 400));
- Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedY() * 400));
- Pkt.WriteShort(static_cast<short>(a_Vehicle.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedX() * 400));
+ Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedY() * 400));
+ Pkt.WriteBEInt16(static_cast<Int16>(a_Vehicle.GetSpeedZ() * 400));
}
}
@@ -1213,7 +1220,7 @@ void cProtocol172::SendStatistics(const cStatManager & a_Manager)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x37);
- Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
+ Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
for (size_t i = 0; i < (size_t)statCount; ++i)
{
@@ -1221,7 +1228,7 @@ void cProtocol172::SendStatistics(const cStatManager & a_Manager)
const AString & StatName = cStatInfo::GetName((eStatistic) i);
Pkt.WriteString(StatName);
- Pkt.WriteVarInt(static_cast<UInt32>(Value));
+ Pkt.WriteVarInt32(static_cast<UInt32>(Value));
}
}
@@ -1234,7 +1241,7 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Results.size()));
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_Results.size()));
for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
{
@@ -1251,7 +1258,7 @@ void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x18);
- Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
Pkt.WriteFPInt(a_Entity.GetPosX());
Pkt.WriteFPInt(a_Entity.GetPosY());
Pkt.WriteFPInt(a_Entity.GetPosZ());
@@ -1268,8 +1275,8 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
- Pkt.WriteVarInt(0); // EntityID = 0, always
- Pkt.WriteByte(1); // Type = Thunderbolt
+ Pkt.WriteVarInt32(0); // EntityID = 0, always
+ Pkt.WriteBEUInt8(1); // Type = Thunderbolt
Pkt.WriteFPInt(a_BlockX);
Pkt.WriteFPInt(a_BlockY);
Pkt.WriteFPInt(a_BlockZ);
@@ -1289,8 +1296,8 @@ void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_Do
}
cPacketizer Pkt(*this, 0x03);
- Pkt.WriteInt64(a_WorldAge);
- Pkt.WriteInt64(a_TimeOfDay);
+ Pkt.WriteBEInt64(a_WorldAge);
+ Pkt.WriteBEInt64(a_TimeOfDay);
}
@@ -1302,12 +1309,12 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
- Pkt.WriteInt(a_ChunkX);
- Pkt.WriteInt(a_ChunkZ);
+ Pkt.WriteBEInt32(a_ChunkX);
+ Pkt.WriteBEInt32(a_ChunkZ);
Pkt.WriteBool(true);
- Pkt.WriteShort(0); // Primary bitmap
- Pkt.WriteShort(0); // Add bitmap
- Pkt.WriteInt(0); // Compressed data size
+ Pkt.WriteBEInt16(0); // Primary bitmap
+ Pkt.WriteBEInt16(0); // Add bitmap
+ Pkt.WriteBEInt32(0); // Compressed data size
}
@@ -1318,9 +1325,9 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x35); // Update tile entity packet
- Pkt.WriteInt(a_BlockEntity.GetPosX());
- Pkt.WriteShort(static_cast<short>(a_BlockEntity.GetPosY()));
- Pkt.WriteInt(a_BlockEntity.GetPosZ());
+ Pkt.WriteBEInt32(a_BlockEntity.GetPosX());
+ Pkt.WriteBEInt16(static_cast<short>(a_BlockEntity.GetPosY()));
+ Pkt.WriteBEInt32(a_BlockEntity.GetPosZ());
Byte Action = 0;
switch (a_BlockEntity.GetBlockType())
@@ -1332,9 +1339,9 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
}
- Pkt.WriteByte(Action);
+ Pkt.WriteBEUInt8(Action);
- Pkt.WriteBlockEntity(a_BlockEntity);
+ WriteBlockEntity(Pkt, a_BlockEntity);
}
@@ -1347,9 +1354,9 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
ASSERT((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height));
cPacketizer Pkt(*this, 0x33);
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteShort((short)a_BlockY);
- Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEInt16(static_cast<Int16>(a_BlockY));
+ Pkt.WriteBEInt32(a_BlockZ);
// Need to send only up to 15 chars, otherwise the client crashes (#598)
Pkt.WriteString(a_Line1.substr(0, 15));
Pkt.WriteString(a_Line2.substr(0, 15));
@@ -1364,12 +1371,13 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
{
ASSERT(m_State == 3); // In game mode?
+ ASSERT((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height));
cPacketizer Pkt(*this, 0x0a);
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteInt(a_BlockX);
- Pkt.WriteByte((Byte)a_BlockY);
- Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt32(a_BlockX);
+ Pkt.WriteBEUInt8(static_cast<Byte>(a_BlockY));
+ Pkt.WriteBEInt32(a_BlockZ);
}
@@ -1382,8 +1390,8 @@ void cProtocol172::SendWeather(eWeather a_Weather)
{
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
- Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
- Pkt.WriteFloat(0); // Unused for weather
+ Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
+ Pkt.WriteBEFloat(0); // Unused for weather
}
// TODO: Fade effect, somehow
@@ -1398,13 +1406,13 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x30); // Window Items packet
- Pkt.WriteChar(a_Window.GetWindowID());
- Pkt.WriteShort(static_cast<short>(a_Window.GetNumSlots()));
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
+ Pkt.WriteBEInt16(static_cast<short>(a_Window.GetNumSlots()));
cItems Slots;
a_Window.GetSlots(*(m_Client->GetPlayer()), Slots);
for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr)
{
- Pkt.WriteItem(*itr);
+ WriteItem(Pkt, *itr);
} // for itr - Slots[]
}
@@ -1417,7 +1425,7 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e);
- Pkt.WriteChar(a_Window.GetWindowID());
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
}
@@ -1435,14 +1443,14 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window)
}
cPacketizer Pkt(*this, 0x2d);
- Pkt.WriteChar(a_Window.GetWindowID());
- Pkt.WriteChar(static_cast<char>(a_Window.GetWindowType()));
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
+ Pkt.WriteBEInt8(static_cast<char>(a_Window.GetWindowType()));
Pkt.WriteString(a_Window.GetWindowTitle());
- Pkt.WriteChar(static_cast<char>(a_Window.GetNumNonInventorySlots()));
+ Pkt.WriteBEInt8(static_cast<char>(a_Window.GetNumNonInventorySlots()));
Pkt.WriteBool(true);
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
{
- Pkt.WriteInt(0); // TODO: The animal's EntityID
+ Pkt.WriteBEInt32(0); // TODO: The animal's EntityID
}
}
@@ -1455,9 +1463,9 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x31); // Window Property packet
- Pkt.WriteChar(a_Window.GetWindowID());
- Pkt.WriteShort(a_Property);
- Pkt.WriteShort(a_Value);
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
+ Pkt.WriteBEInt16(a_Property);
+ Pkt.WriteBEInt16(a_Value);
}
@@ -1556,7 +1564,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size)
bb.ReadAll(Packet);
Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
AString Out;
- CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24);
+ CreateHexDump(Out, Packet.data(), Packet.size(), 24);
LOGD("Packet contents:\n%s", Out.c_str());
#endif // _DEBUG
@@ -1702,7 +1710,7 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp);
cPacketizer Pkt(*this, 0x01); // Ping packet
- Pkt.WriteInt64(Timestamp);
+ Pkt.WriteBEInt64(Timestamp);
}
@@ -1756,49 +1764,52 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer)
{
- short EncKeyLength, EncNonceLength;
- if (!a_ByteBuffer.ReadBEShort(EncKeyLength))
+ UInt16 EncKeyLength, EncNonceLength;
+ if (!a_ByteBuffer.ReadBEUInt16(EncKeyLength))
{
return;
}
- if ((EncKeyLength < 0) || (EncKeyLength > MAX_ENC_LEN))
+ if (EncKeyLength > MAX_ENC_LEN)
{
- LOGD("Invalid Encryption Key length: %d. Kicking client.", EncKeyLength);
+ LOGD("Invalid Encryption Key length: %u (0x%04x). Kicking client.", EncKeyLength, EncKeyLength);
m_Client->Kick("Invalid EncKeyLength");
return;
}
AString EncKey;
- if (!a_ByteBuffer.ReadString(EncKey, static_cast<size_t>(EncKeyLength)))
+ if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
{
return;
}
- if (!a_ByteBuffer.ReadBEShort(EncNonceLength))
+ if (!a_ByteBuffer.ReadBEUInt16(EncNonceLength))
{
return;
}
- if ((EncNonceLength < 0) || (EncNonceLength > MAX_ENC_LEN))
+ if (EncNonceLength > MAX_ENC_LEN)
{
- LOGD("Invalid Encryption Nonce length: %d. Kicking client.", EncNonceLength);
+ LOGD("Invalid Encryption Nonce length: %u (0x%04x). Kicking client.", EncNonceLength, EncNonceLength);
m_Client->Kick("Invalid EncNonceLength");
return;
}
AString EncNonce;
- if (!a_ByteBuffer.ReadString(EncNonce, static_cast<size_t>(EncNonceLength)))
+ if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
{
return;
}
// Decrypt EncNonce using privkey
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
- Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
- int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
+ UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(UInt32)];
+ int res = rsaDecryptor.Decrypt(
+ reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(),
+ reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce)
+ );
if (res != 4)
{
LOGD("Bad nonce length: got %d, exp %d", res, 4);
m_Client->Kick("Hacked client");
return;
}
- if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this)
+ if (ntohl(DecryptedNonce[0]) != static_cast<UInt32>(reinterpret_cast<uintptr_t>(this)))
{
LOGD("Bad nonce value");
m_Client->Kick("Hacked client");
@@ -1807,7 +1818,10 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
// Decrypt the symmetric encryption key using privkey:
Byte DecryptedKey[MAX_ENC_LEN];
- res = rsaDecryptor.Decrypt((const Byte *)EncKey.data(), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
+ res = rsaDecryptor.Decrypt(
+ reinterpret_cast<const Byte *>(EncKey.data()), EncKey.size(),
+ DecryptedKey, sizeof(DecryptedKey)
+ );
if (res != 16)
{
LOGD("Bad key length");
@@ -1845,10 +1859,10 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
cPacketizer Pkt(*this, 0x01);
Pkt.WriteString(Server->GetServerID());
const AString & PubKeyDer = Server->GetPublicKeyDER();
- Pkt.WriteShort((short)PubKeyDer.size());
+ Pkt.WriteBEUInt16(static_cast<UInt16>(PubKeyDer.size()));
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
- Pkt.WriteShort(4);
- Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
+ Pkt.WriteBEInt16(4);
+ Pkt.WriteBEUInt32(static_cast<UInt32>(reinterpret_cast<uintptr_t>(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
m_Client->SetUsername(Username);
return;
}
@@ -1862,8 +1876,8 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Animation);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Animation);
m_Client->HandleAnimation(Animation);
}
@@ -1873,12 +1887,12 @@ void cProtocol172::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, Status);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ);
- HANDLE_READ(a_ByteBuffer, ReadChar, char, Face);
- m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), Status);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, BlockY);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
+ m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), Status);
}
@@ -1887,17 +1901,17 @@ void cProtocol172::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ);
- HANDLE_READ(a_ByteBuffer, ReadChar, char, Face);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, BlockY);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
cItem Item;
ReadItem(a_ByteBuffer, Item);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorX);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorY);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
}
@@ -1917,11 +1931,11 @@ void cProtocol172::HandlePacketChatMessage(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ViewDistance);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatFlags);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatColors);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Difficulty);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ShowCape);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatColors);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Difficulty);
+ HANDLE_READ(a_ByteBuffer, ReadBool, bool, ShowCape);
m_Client->SetLocale(Locale);
m_Client->SetViewDistance(ViewDistance);
@@ -1934,7 +1948,7 @@ void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ActionID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID);
switch (ActionID)
{
case 0:
@@ -1966,13 +1980,13 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
cItem Item;
if (!ReadItem(a_ByteBuffer, Item))
{
return;
}
- m_Client->HandleCreativeInventory(SlotNum, Item);
+ m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum < 0) ? caLeftClick : caLeftClickOutside);
}
@@ -1981,9 +1995,9 @@ void cProtocol172::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffe
void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, PlayerID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Action);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, JumpBoost);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, PlayerID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, JumpBoost);
switch (Action)
{
@@ -2001,7 +2015,7 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, KeepAliveID);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, KeepAliveID);
m_Client->HandleKeepAlive(KeepAliveID);
}
@@ -2021,10 +2035,11 @@ void cProtocol172::HandlePacketPlayer(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketPlayerAbilities(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Flags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed);
+ // Convert flags bitfield into individual bool flags:
bool IsFlying = false, CanFly = false;
if ((Flags & 2) != 0)
{
@@ -2087,11 +2102,11 @@ void cProtocol172::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length);
- if (Length + 1 != (int)a_ByteBuffer.GetReadableSpace())
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, Length);
+ if (Length != a_ByteBuffer.GetReadableSpace() - 1)
{
- LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %d, got %d)",
- static_cast<int>(a_ByteBuffer.GetReadableSpace()) - 1, Length
+ LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %u, got %u)",
+ static_cast<unsigned>(a_ByteBuffer.GetReadableSpace() - 1), Length
);
return;
}
@@ -2105,7 +2120,7 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
// Read the plugin message and relay to clienthandle:
AString Data;
- if (!a_ByteBuffer.ReadString(Data, static_cast<size_t>(Length)))
+ if (!a_ByteBuffer.ReadString(Data, Length))
{
return;
}
@@ -2118,7 +2133,7 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
m_Client->HandleSlotSelected(SlotNum);
}
@@ -2158,9 +2173,9 @@ void cProtocol172::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, BlockY);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, BlockY);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line1);
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line2);
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Line3);
@@ -2174,8 +2189,8 @@ void cProtocol172::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, MouseButton);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, MouseButton);
m_Client->HandleUseEntity(EntityID, (MouseButton == 1));
}
@@ -2185,8 +2200,8 @@ 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);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment);
m_Client->HandleEnchantItem(WindowID, Enchantment);
}
@@ -2197,11 +2212,11 @@ void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Button);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, TransactionID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode);
cItem Item;
ReadItem(a_ByteBuffer, Item);
@@ -2209,8 +2224,8 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
eClickAction Action;
switch ((Mode << 8) | Button)
{
- case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break;
- case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break;
+ case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break;
+ case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break;
case 0x0100: Action = caShiftLeftClick; break;
case 0x0101: Action = caShiftRightClick; break;
case 0x0200: Action = caNumber1; break;
@@ -2223,14 +2238,14 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
case 0x0207: Action = caNumber8; break;
case 0x0208: Action = caNumber9; break;
case 0x0300: Action = caMiddleClick; break;
- case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break;
- case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
- case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break;
- case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break;
- case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break;
- case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break;
- case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break;
- case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break;
+ case 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break;
+ case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
+ case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break;
+ case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break;
+ case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break;
+ case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break;
+ case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break;
+ case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break;
case 0x0600: Action = caDblClick; break;
default:
{
@@ -2249,7 +2264,7 @@ void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
m_Client->HandleWindowClose(WindowID);
}
@@ -2257,20 +2272,20 @@ void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer)
-void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength)
+void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, UInt16 a_PayloadLength)
{
if (a_Channel == "MC|AdvCdm")
{
size_t BeginningSpace = a_ByteBuffer.GetReadableSpace();
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode);
switch (Mode)
{
case 0x00:
{
// Block-based commandblock update:
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command);
m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command);
break;
@@ -2288,12 +2303,12 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
// Read the remainder of the packet (Vanilla sometimes sends bogus data at the end of the packet; #1692):
size_t BytesRead = BeginningSpace - a_ByteBuffer.GetReadableSpace();
- if (BytesRead < static_cast<size_t>(a_PayloadLength))
+ if (BytesRead < a_PayloadLength)
{
LOGD("Protocol 1.7: Skipping garbage data at the end of a vanilla MC|AdvCdm packet, %u bytes",
static_cast<unsigned>(a_PayloadLength - BytesRead)
);
- a_ByteBuffer.SkipRead(static_cast<size_t>(a_PayloadLength) - BytesRead);
+ a_ByteBuffer.SkipRead(a_PayloadLength - BytesRead);
}
return;
}
@@ -2301,7 +2316,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
{
// Read the client's brand:
AString Brand;
- if (a_ByteBuffer.ReadString(Brand, static_cast<size_t>(a_PayloadLength)))
+ if (a_ByteBuffer.ReadString(Brand, a_PayloadLength))
{
m_Client->SetClientBrand(Brand);
}
@@ -2312,15 +2327,15 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
else if (a_Channel == "MC|Beacon")
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2);
m_Client->HandleBeaconSelection(Effect1, Effect2);
return;
}
else if (a_Channel == "MC|ItemName")
{
AString ItemName;
- if (a_ByteBuffer.ReadString(ItemName, static_cast<size_t>(a_PayloadLength)))
+ if (a_ByteBuffer.ReadString(ItemName, a_PayloadLength))
{
m_Client->HandleAnvilItemName(ItemName);
}
@@ -2328,7 +2343,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
else if (a_Channel == "MC|TrSel")
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum);
m_Client->HandleNPCTrade(SlotNum);
return;
}
@@ -2336,7 +2351,7 @@ void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
// Read the payload and send it through to the clienthandle:
AString Message;
- VERIFY(a_ByteBuffer.ReadString(Message, static_cast<size_t>(a_PayloadLength)));
+ VERIFY(a_ByteBuffer.ReadString(Message, a_PayloadLength));
m_Client->HandlePluginMessage(a_Channel, Message);
}
@@ -2368,9 +2383,42 @@ void cProtocol172::SendData(const char * a_Data, size_t a_Size)
+void cProtocol172::SendPacket(cPacketizer & a_Packet)
+{
+ AString DataToSend;
+
+ // Send the packet length
+ UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
+
+ m_OutPacketLenBuffer.WriteVarInt32(PacketLen);
+ m_OutPacketLenBuffer.ReadAll(DataToSend);
+ SendData(DataToSend.data(), DataToSend.size());
+ m_OutPacketLenBuffer.CommitRead();
+
+ // Send the packet data:
+ m_OutPacketBuffer.ReadAll(DataToSend);
+ SendData(DataToSend.data(), DataToSend.size());
+ m_OutPacketBuffer.CommitRead();
+
+ // Log the comm into logfile:
+ if (g_ShouldLogCommOut)
+ {
+ AString Hex;
+ ASSERT(DataToSend.size() > 0);
+ CreateHexDump(Hex, DataToSend.data(), DataToSend.size(), 16);
+ m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload (incl. type):\n%s\n",
+ a_Packet.GetPacketType(), a_Packet.GetPacketType(), PacketLen, PacketLen, m_State, Hex.c_str()
+ );
+ }
+}
+
+
+
+
+
bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item)
{
- HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemType);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType);
if (ItemType == -1)
{
// The item is empty, no more data follows
@@ -2379,8 +2427,8 @@ bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item)
}
a_Item.m_ItemType = ItemType;
- HANDLE_PACKET_READ(a_ByteBuffer, ReadChar, char, ItemCount);
- HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemDamage);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage);
a_Item.m_ItemCount = ItemCount;
a_Item.m_ItemDamage = ItemDamage;
if (ItemCount <= 0)
@@ -2388,15 +2436,10 @@ bool cProtocol172::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item)
a_Item.Empty();
}
- HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, MetadataLength);
- if (MetadataLength <= 0)
- {
- return true;
- }
-
// Read the metadata
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEUInt16, UInt16, MetadataLength);
AString Metadata;
- if (!a_ByteBuffer.ReadString(Metadata, static_cast<size_t>(MetadataLength)))
+ if (!a_ByteBuffer.ReadString(Metadata, MetadataLength))
{
return false;
}
@@ -2512,35 +2555,19 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
-////////////////////////////////////////////////////////////////////////////////
-// cProtocol172::cPacketizer:
-
-cProtocol172::cPacketizer::~cPacketizer()
+eBlockFace cProtocol172::FaceIntToBlockFace(Int8 a_BlockFace)
{
- AString DataToSend;
-
- // Send the packet length
- UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace();
-
- m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen);
- m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend);
- m_Protocol.SendData(DataToSend.data(), DataToSend.size());
- m_Protocol.m_OutPacketLenBuffer.CommitRead();
-
- // Send the packet data:
- m_Out.ReadAll(DataToSend);
- m_Protocol.SendData(DataToSend.data(), DataToSend.size());
- m_Out.CommitRead();
-
- // Log the comm into logfile:
- if (g_ShouldLogCommOut)
+ // Normalize the blockface values returned from the protocol
+ // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE
+ switch (a_BlockFace)
{
- AString Hex;
- ASSERT(DataToSend.size() > 0);
- CreateHexDump(Hex, DataToSend.data() + 1, DataToSend.size() - 1, 16);
- m_Protocol.m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload:\n%s\n",
- DataToSend[0], DataToSend[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str()
- );
+ case BLOCK_FACE_XM: return BLOCK_FACE_XM;
+ case BLOCK_FACE_XP: return BLOCK_FACE_XP;
+ case BLOCK_FACE_YM: return BLOCK_FACE_YM;
+ case BLOCK_FACE_YP: return BLOCK_FACE_YP;
+ case BLOCK_FACE_ZM: return BLOCK_FACE_ZM;
+ case BLOCK_FACE_ZP: return BLOCK_FACE_ZP;
+ default: return BLOCK_FACE_NONE;
}
}
@@ -2548,7 +2575,7 @@ cProtocol172::cPacketizer::~cPacketizer()
-void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
+void cProtocol172::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
{
short ItemType = a_Item.m_ItemType;
ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
@@ -2560,17 +2587,17 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
if (a_Item.IsEmpty())
{
- WriteShort(-1);
+ a_Pkt.WriteBEInt16(-1);
return;
}
- WriteShort(ItemType);
- WriteChar (a_Item.m_ItemCount);
- WriteShort(a_Item.m_ItemDamage);
+ a_Pkt.WriteBEInt16(ItemType);
+ a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
+ a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR))
{
- WriteShort(-1);
+ a_Pkt.WriteBEInt16(-1);
return;
}
@@ -2619,15 +2646,15 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort((short)Compressed.size());
- WriteBuf(Compressed.data(), Compressed.size());
+ a_Pkt.WriteBEUInt16(static_cast<UInt16>(Compressed.size()));
+ a_Pkt.WriteBuf(Compressed.data(), Compressed.size());
}
-void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity)
+void cProtocol172::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity)
{
cFastNBTWriter Writer;
@@ -2635,46 +2662,41 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
{
case E_BLOCK_BEACON:
{
- cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity;
-
- Writer.AddInt("x", BeaconEntity.GetPosX());
- Writer.AddInt("y", BeaconEntity.GetPosY());
- Writer.AddInt("z", BeaconEntity.GetPosZ());
- Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
+ auto & BeaconEntity = reinterpret_cast<const cBeaconEntity &>(a_BlockEntity);
+ Writer.AddInt("x", BeaconEntity.GetPosX());
+ Writer.AddInt("y", BeaconEntity.GetPosY());
+ Writer.AddInt("z", BeaconEntity.GetPosZ());
+ Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect());
- Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
+ Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_COMMAND_BLOCK:
{
- cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity;
-
+ auto & CommandBlockEntity = reinterpret_cast<const cCommandBlockEntity &>(a_BlockEntity);
Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
- Writer.AddInt("x", CommandBlockEntity.GetPosX());
- Writer.AddInt("y", CommandBlockEntity.GetPosY());
- Writer.AddInt("z", CommandBlockEntity.GetPosZ());
- Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str());
+ Writer.AddInt("x", CommandBlockEntity.GetPosX());
+ Writer.AddInt("y", CommandBlockEntity.GetPosY());
+ Writer.AddInt("z", CommandBlockEntity.GetPosZ());
+ Writer.AddString("Command", CommandBlockEntity.GetCommand().c_str());
// You can set custom names for windows in Vanilla
// For a command block, this would be the 'name' prepended to anything it outputs into global chat
- // MCS doesn't have this, so just leave it @ '@'. (geddit?)
+ // MCS doesn't have this, so just leave it at '@'.
Writer.AddString("CustomName", "@");
- Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
-
+ Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
if (!CommandBlockEntity.GetLastOutput().empty())
{
- AString Output;
- Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str());
-
- Writer.AddString("LastOutput", Output.c_str());
+ Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()));
}
break;
}
+
case E_BLOCK_HEAD:
{
- cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity;
-
+ auto & MobHeadEntity = reinterpret_cast<const cMobHeadEntity &>(a_BlockEntity);
Writer.AddInt("x", MobHeadEntity.GetPosX());
Writer.AddInt("y", MobHeadEntity.GetPosY());
Writer.AddInt("z", MobHeadEntity.GetPosZ());
@@ -2684,10 +2706,10 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_FLOWER_POT:
{
- cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity;
-
+ auto & FlowerPotEntity = reinterpret_cast<const cFlowerPotEntity &>(a_BlockEntity);
Writer.AddInt("x", FlowerPotEntity.GetPosX());
Writer.AddInt("y", FlowerPotEntity.GetPosY());
Writer.AddInt("z", FlowerPotEntity.GetPosZ());
@@ -2696,10 +2718,10 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_MOB_SPAWNER:
{
- cMobSpawnerEntity & MobSpawnerEntity = (cMobSpawnerEntity &)a_BlockEntity;
-
+ auto & MobSpawnerEntity = reinterpret_cast<const cMobSpawnerEntity &>(a_BlockEntity);
Writer.AddInt("x", MobSpawnerEntity.GetPosX());
Writer.AddInt("y", MobSpawnerEntity.GetPosY());
Writer.AddInt("z", MobSpawnerEntity.GetPosZ());
@@ -2708,41 +2730,26 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "MobSpawner");
break;
}
- default: break;
+
+ default:
+ {
+ break;
+ }
}
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort((short)Compressed.size());
- WriteBuf(Compressed.data(), Compressed.size());
+ a_Pkt.WriteBEUInt16(static_cast<UInt16>(Compressed.size()));
+ a_Pkt.WriteBuf(Compressed.data(), Compressed.size());
}
-void cProtocol172::cPacketizer::WriteByteAngle(double a_Angle)
-{
- WriteChar(static_cast<char>(255 * a_Angle / 360));
-}
-
-
-
-
-
-void cProtocol172::cPacketizer::WriteFPInt(double a_Value)
-{
- int Value = (int)(a_Value * 32);
- WriteInt(Value);
-}
-
-
-
-
-
-void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
+void cProtocol172::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
// Common metadata:
Byte Flags = 0;
@@ -2766,21 +2773,21 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
{
Flags |= 0x20;
}
- WriteByte(0); // Byte(0) + index 0
- WriteByte(Flags);
+ a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0
+ a_Pkt.WriteBEUInt8(Flags);
switch (a_Entity.GetEntityType())
{
case cEntity::etPlayer: break; // TODO?
case cEntity::etPickup:
{
- WriteByte((5 << 5) | 10); // Slot(5) + index 10
- WriteItem(((const cPickup &)a_Entity).GetItem());
+ a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10
+ WriteItem(a_Pkt, reinterpret_cast<const cPickup &>(a_Entity).GetItem());
break;
}
case cEntity::etMinecart:
{
- WriteByte(0x51);
+ a_Pkt.WriteBEUInt8(0x51);
// The following expression makes Minecarts shake more with less health or higher damage taken
// It gets half the maximum health, and takes it away from the current health minus the half health:
@@ -2789,263 +2796,274 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
Health: 3 | 3 - (3 - 3) = 3
Health: 1 | 3 - (1 - 3) = 5
*/
- WriteInt((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4);
- WriteByte(0x52);
- WriteInt(1); // Shaking direction, doesn't seem to affect anything
- WriteByte(0x73);
- WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
+ auto & Minecart = reinterpret_cast<const cMinecart &>(a_Entity);
+ a_Pkt.WriteBEInt32((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4);
+ a_Pkt.WriteBEUInt8(0x52);
+ a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything
+ a_Pkt.WriteBEUInt8(0x73);
+ a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10)); // Damage taken / shake effect multiplyer
- if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
+ if (Minecart.GetPayload() == cMinecart::mpNone)
{
- cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
+ auto & RideableMinecart = reinterpret_cast<const cRideableMinecart &>(Minecart);
const cItem & MinecartContent = RideableMinecart.GetContent();
if (!MinecartContent.IsEmpty())
{
- WriteByte(0x54);
+ a_Pkt.WriteBEUInt8(0x54);
int Content = MinecartContent.m_ItemType;
Content |= MinecartContent.m_ItemDamage << 8;
- WriteInt(Content);
- WriteByte(0x55);
- WriteInt(RideableMinecart.GetBlockHeight());
- WriteByte(0x56);
- WriteByte(1);
+ a_Pkt.WriteBEInt32(Content);
+ a_Pkt.WriteBEUInt8(0x55);
+ a_Pkt.WriteBEInt32(RideableMinecart.GetBlockHeight());
+ a_Pkt.WriteBEUInt8(0x56);
+ a_Pkt.WriteBEUInt8(1);
}
}
- else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
+ else if (Minecart.GetPayload() == cMinecart::mpFurnace)
{
- WriteByte(0x10);
- WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cMinecartWithFurnace &>(Minecart).IsFueled() ? 1 : 0);
}
break;
- }
+ } // case etMinecart
+
case cEntity::etProjectile:
{
- cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
+ auto & Projectile = reinterpret_cast<const cProjectileEntity &>(a_Entity);
switch (Projectile.GetProjectileKind())
{
case cProjectileEntity::pkArrow:
{
- WriteByte(0x10);
- WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cArrowEntity &>(a_Entity).IsCritical() ? 1 : 0);
break;
}
case cProjectileEntity::pkFirework:
{
- WriteByte(0xA8);
- WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
+ a_Pkt.WriteBEUInt8(0xa8);
+ WriteItem(a_Pkt, reinterpret_cast<const cFireworkEntity &>(a_Entity).GetItem());
break;
}
default: break;
}
break;
- }
+ } // case etProjectile
+
case cEntity::etMonster:
{
- WriteMobMetadata((const cMonster &)a_Entity);
+ WriteMobMetadata(a_Pkt, reinterpret_cast<const cMonster &>(a_Entity));
break;
- }
+ } // case etMonster
+
case cEntity::etItemFrame:
{
- cItemFrame & Frame = (cItemFrame &)a_Entity;
- WriteByte(0xA2);
- WriteItem(Frame.GetItem());
- WriteByte(0x3);
- WriteByte(Frame.GetItemRotation() / 2);
+ auto & Frame = reinterpret_cast<const cItemFrame &>(a_Entity);
+ a_Pkt.WriteBEUInt8(0xa2);
+ WriteItem(a_Pkt, Frame.GetItem());
+ a_Pkt.WriteBEUInt8(0x03);
+ a_Pkt.WriteBEUInt8(Frame.GetItemRotation() / 2);
+ break;
+ } // case etItemFrame
+
+ default:
+ {
break;
}
- default: break;
- }
+ } // switch (EntityType)
}
-void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
+void cProtocol172::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob)
{
switch (a_Mob.GetMobType())
{
- case mtCreeper:
- {
- WriteByte(0x10);
- WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : 0);
- WriteByte(0x11);
- WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0);
- break;
- }
-
case mtBat:
{
- WriteByte(0x10);
- WriteByte(((const cBat &)a_Mob).IsHanging() ? 1 : 0);
- break;
- }
-
- case mtPig:
- {
- WriteByte(0x10);
- WriteByte(((const cPig &)a_Mob).IsSaddled() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cBat &>(a_Mob).IsHanging() ? 1 : 0);
break;
- }
+ } // case mtBat
- case mtVillager:
+ case mtCreeper:
{
- WriteByte(0x50);
- WriteInt(((const cVillager &)a_Mob).GetVilType());
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cCreeper &>(a_Mob).IsBlowing() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x11);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cCreeper &>(a_Mob).IsCharged() ? 1 : 0);
break;
- }
+ } // case mtCreeper
- case mtZombie:
+ case mtEnderman:
{
- WriteByte(0x0c);
- WriteByte(((const cZombie &)a_Mob).IsBaby() ? 1 : 0);
- WriteByte(0x0d);
- WriteByte(((const cZombie &)a_Mob).IsVillagerZombie() ? 1 : 0);
- WriteByte(0x0e);
- WriteByte(((const cZombie &)a_Mob).IsConverting() ? 1 : 0);
+ auto & Enderman = reinterpret_cast<const cEnderman &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8((Byte)(Enderman.GetCarriedBlock()));
+ a_Pkt.WriteBEUInt8(0x11);
+ a_Pkt.WriteBEUInt8((Byte)(Enderman.GetCarriedMeta()));
+ a_Pkt.WriteBEUInt8(0x12);
+ a_Pkt.WriteBEUInt8(Enderman.IsScreaming() ? 1 : 0);
break;
- }
+ } // case mtEnderman
case mtGhast:
{
- WriteByte(0x10);
- WriteByte(((const cGhast &)a_Mob).IsCharging());
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cGhast &>(a_Mob).IsCharging());
break;
- }
+ } // case mtGhast
- case mtWolf:
+ case mtHorse:
{
- const cWolf & Wolf = (const cWolf &)a_Mob;
- Byte WolfStatus = 0;
- if (Wolf.IsSitting())
+ auto & Horse = reinterpret_cast<const cHorse &>(a_Mob);
+ int Flags = 0;
+ if (Horse.IsTame())
{
- WolfStatus |= 0x1;
+ Flags |= 0x02;
}
- if (Wolf.IsAngry())
+ if (Horse.IsSaddled())
{
- WolfStatus |= 0x2;
+ Flags |= 0x04;
}
- if (Wolf.IsTame())
+ if (Horse.IsChested())
{
- WolfStatus |= 0x4;
+ Flags |= 0x08;
}
- WriteByte(0x10);
- WriteByte(WolfStatus);
-
- WriteByte(0x72);
- WriteFloat((float)(a_Mob.GetHealth()));
- WriteByte(0x13);
- WriteByte(Wolf.IsBegging() ? 1 : 0);
- WriteByte(0x14);
- WriteByte(static_cast<Byte>(Wolf.GetCollarColor()));
+ if (Horse.IsBaby())
+ {
+ Flags |= 0x10;
+ }
+ if (Horse.IsEating())
+ {
+ Flags |= 0x20;
+ }
+ if (Horse.IsRearing())
+ {
+ Flags |= 0x40;
+ }
+ if (Horse.IsMthOpen())
+ {
+ Flags |= 0x80;
+ }
+ a_Pkt.WriteBEUInt8(0x50); // Int at index 16
+ a_Pkt.WriteBEInt32(Flags);
+ a_Pkt.WriteBEUInt8(0x13); // Byte at index 19
+ a_Pkt.WriteBEUInt8(static_cast<Byte>(Horse.GetHorseType()));
+ a_Pkt.WriteBEUInt8(0x54); // Int at index 20
+ int Appearance = 0;
+ Appearance = Horse.GetHorseColor();
+ Appearance |= Horse.GetHorseStyle() << 8;
+ a_Pkt.WriteBEInt32(Appearance);
+ a_Pkt.WriteBEUInt8(0x56); // Int at index 22
+ a_Pkt.WriteBEInt32(Horse.GetHorseArmour());
break;
- }
+ } // case mtHorse
+
+ case mtMagmaCube:
+ {
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(static_cast<Byte>(reinterpret_cast<const cMagmaCube &>(a_Mob).GetSize()));
+ break;
+ } // case mtMagmaCube
+
+ case mtPig:
+ {
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cPig &>(a_Mob).IsSaddled() ? 1 : 0);
+ break;
+ } // case mtPig
case mtSheep:
{
- WriteByte(0x10);
- Byte SheepMetadata = static_cast<Byte>(((const cSheep &)a_Mob).GetFurColor() & 0x0f);
- if (((const cSheep &)a_Mob).IsSheared())
+ a_Pkt.WriteBEUInt8(0x10);
+ auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob);
+ Byte SheepMetadata = static_cast<Byte>(Sheep.GetFurColor() & 0x0f);
+ if (Sheep.IsSheared())
{
SheepMetadata |= 0x10;
}
- WriteByte(SheepMetadata);
+ a_Pkt.WriteBEUInt8(SheepMetadata);
break;
- }
-
- case mtEnderman:
- {
- WriteByte(0x10);
- WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedBlock()));
- WriteByte(0x11);
- WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedMeta()));
- WriteByte(0x12);
- WriteByte(((const cEnderman &)a_Mob).IsScreaming() ? 1 : 0);
- break;
- }
+ } // case mtSheep
case mtSkeleton:
{
- WriteByte(0x0d);
- WriteByte(((const cSkeleton &)a_Mob).IsWither() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x0d);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cSkeleton &>(a_Mob).IsWither() ? 1 : 0);
break;
- }
+ } // case mtSkeleton
- case mtWitch:
+ case mtSlime:
{
- WriteByte(0x15);
- WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(static_cast<Byte>(reinterpret_cast<const cSlime &>(a_Mob).GetSize()));
break;
- }
-
- case mtWither:
+ } // case mtSlime
+
+ case mtVillager:
{
- WriteByte(0x54); // Int at index 20
- WriteInt(static_cast<int>(((const cWither &)a_Mob).GetWitherInvulnerableTicks()));
- WriteByte(0x66); // Float at index 6
- WriteFloat((float)(a_Mob.GetHealth()));
+ a_Pkt.WriteBEUInt8(0x50);
+ a_Pkt.WriteBEInt32(reinterpret_cast<const cVillager &>(a_Mob).GetVilType());
break;
- }
+ } // case mtVillager
- case mtSlime:
+ case mtWitch:
{
- WriteByte(0x10);
- WriteByte(static_cast<Byte>(((const cSlime &)a_Mob).GetSize()));
+ a_Pkt.WriteBEUInt8(0x15);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cWitch &>(a_Mob).IsAngry() ? 1 : 0);
break;
- }
-
- case mtMagmaCube:
+ } // case mtWitch
+
+ case mtWither:
{
- WriteByte(0x10);
- WriteByte(static_cast<Byte>(((const cMagmaCube &)a_Mob).GetSize()));
+ a_Pkt.WriteBEUInt8(0x54); // Int at index 20
+ a_Pkt.WriteBEInt32(static_cast<int>(reinterpret_cast<const cWither &>(a_Mob).GetWitherInvulnerableTicks()));
+ a_Pkt.WriteBEUInt8(0x66); // Float at index 6
+ a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
break;
- }
+ } // case mtWither
- case mtHorse:
+ case mtWolf:
{
- const cHorse & Horse = (const cHorse &)a_Mob;
- int Flags = 0;
- if (Horse.IsTame())
- {
- Flags |= 0x02;
- }
- if (Horse.IsSaddled())
- {
- Flags |= 0x04;
- }
- if (Horse.IsChested())
- {
- Flags |= 0x08;
- }
- if (Horse.IsBaby())
- {
- Flags |= 0x10;
- }
- if (Horse.IsEating())
+ auto & Wolf = reinterpret_cast<const cWolf &>(a_Mob);
+ Byte WolfStatus = 0;
+ if (Wolf.IsSitting())
{
- Flags |= 0x20;
+ WolfStatus |= 0x1;
}
- if (Horse.IsRearing())
+ if (Wolf.IsAngry())
{
- Flags |= 0x40;
+ WolfStatus |= 0x2;
}
- if (Horse.IsMthOpen())
+ if (Wolf.IsTame())
{
- Flags |= 0x80;
+ WolfStatus |= 0x4;
}
- WriteByte(0x50); // Int at index 16
- WriteInt(Flags);
- WriteByte(0x13); // Byte at index 19
- WriteByte(static_cast<Byte>(Horse.GetHorseType()));
- WriteByte(0x54); // Int at index 20
- int Appearance = 0;
- Appearance = Horse.GetHorseColor();
- Appearance |= Horse.GetHorseStyle() << 8;
- WriteInt(Appearance);
- WriteByte(0x56); // Int at index 22
- WriteInt(Horse.GetHorseArmour());
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(WolfStatus);
+
+ a_Pkt.WriteBEUInt8(0x72);
+ a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
+ a_Pkt.WriteBEUInt8(0x13);
+ a_Pkt.WriteBEUInt8(Wolf.IsBegging() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x14);
+ a_Pkt.WriteBEUInt8(static_cast<Byte>(Wolf.GetCollarColor()));
break;
- }
+ } // case mtWolf
+
+ case mtZombie:
+ {
+ auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x0c);
+ a_Pkt.WriteBEUInt8(Zombie.IsBaby() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x0d);
+ a_Pkt.WriteBEUInt8(Zombie.IsVillagerZombie() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x0e);
+ a_Pkt.WriteBEUInt8(Zombie.IsConverting() ? 1 : 0);
+ break;
+ } // case mtZombie
default:
{
@@ -3057,10 +3075,10 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
// Custom name:
if (a_Mob.HasCustomName())
{
- WriteByte(0x8a);
- WriteString(a_Mob.GetCustomName());
- WriteByte(0x0b);
- WriteByte(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x8a);
+ a_Pkt.WriteString(a_Mob.GetCustomName());
+ a_Pkt.WriteBEUInt8(0x0b);
+ a_Pkt.WriteBEUInt8(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0);
}
}
@@ -3068,20 +3086,20 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
-void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
+void cProtocol172::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
if (!a_Entity.IsMob())
{
// No properties for anything else than mobs
- WriteInt(0);
+ a_Pkt.WriteBEInt32(0);
return;
}
- // const cMonster & Mob = (const cMonster &)a_Entity;
+ // auto & Mob = reinterpret_cast<const cMonster &>(a_Entity);
// TODO: Send properties and modifiers based on the mob type
- WriteInt(0); // NumProperties
+ a_Pkt.WriteBEInt32(0); // NumProperties
}
@@ -3104,7 +3122,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
{
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
- Pkt.WriteVarInt(static_cast<UInt32>(a_Player.GetUniqueID()));
+ Pkt.WriteVarInt32(a_Player.GetUniqueID());
Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID()));
if (a_Player.HasCustomName())
{
@@ -3116,7 +3134,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
}
const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
- Pkt.WriteVarInt(Properties.size());
+ Pkt.WriteVarInt32(Properties.size());
for (Json::Value::iterator itr = Properties.begin(), end = Properties.end(); itr != end; ++itr)
{
@@ -3131,10 +3149,10 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
Pkt.WriteByteAngle(a_Player.GetYaw());
Pkt.WriteByteAngle(a_Player.GetPitch());
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
- Pkt.WriteShort(ItemType);
- Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
- Pkt.WriteFloat((float)a_Player.GetHealth());
- Pkt.WriteByte(0x7f); // Metadata: end
+ Pkt.WriteBEInt16(ItemType);
+ Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6
+ Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth()));
+ Pkt.WriteBEUInt8(0x7f); // Metadata: end
}
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index f939bfb5e..1212cc325 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -63,7 +63,7 @@ public:
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
- virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
+ virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override;
@@ -140,89 +140,6 @@ public:
protected:
- /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */
- class cPacketizer
- {
- public:
- cPacketizer(cProtocol172 & a_Protocol, UInt32 a_PacketType) :
- m_Protocol(a_Protocol),
- m_Out(a_Protocol.m_OutPacketBuffer),
- m_Lock(a_Protocol.m_CSPacket)
- {
- m_Out.WriteVarInt(a_PacketType);
- }
-
- ~cPacketizer();
-
- void WriteBool(bool a_Value)
- {
- m_Out.WriteBool(a_Value);
- }
-
- void WriteByte(Byte a_Value)
- {
- m_Out.WriteByte(a_Value);
- }
-
- void WriteChar(char a_Value)
- {
- m_Out.WriteChar(a_Value);
- }
-
- void WriteShort(short a_Value)
- {
- m_Out.WriteBEShort(a_Value);
- }
-
- void WriteInt(int a_Value)
- {
- m_Out.WriteBEInt(a_Value);
- }
-
- void WriteInt64(Int64 a_Value)
- {
- m_Out.WriteBEInt64(a_Value);
- }
-
- void WriteFloat(float a_Value)
- {
- m_Out.WriteBEFloat(a_Value);
- }
-
- void WriteDouble(double a_Value)
- {
- m_Out.WriteBEDouble(a_Value);
- }
-
- void WriteVarInt(UInt32 a_Value)
- {
- m_Out.WriteVarInt(a_Value);
- }
-
- void WriteString(const AString & a_Value)
- {
- m_Out.WriteVarUTF8String(a_Value);
- }
-
- void WriteBuf(const char * a_Data, size_t a_Size)
- {
- m_Out.Write(a_Data, a_Size);
- }
-
- void WriteItem(const cItem & a_Item);
- void WriteByteAngle(double a_Angle); // Writes the specified angle using a single byte
- void WriteFPInt(double a_Value); // Writes the double value as a 27:5 fixed-point integer
- void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f
- void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob
- void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field
- void WriteBlockEntity(const cBlockEntity & a_BlockEntity);
-
- protected:
- cProtocol172 & m_Protocol;
- cByteBuffer & m_Out;
- cCSLock m_Lock;
- } ;
-
AString m_ServerAddress;
UInt16 m_ServerPort;
@@ -235,12 +152,6 @@ protected:
/** Buffer for the received data */
cByteBuffer m_ReceivedData;
- /** Buffer for composing the outgoing packets, through cPacketizer */
- cByteBuffer m_OutPacketBuffer;
-
- /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */
- cByteBuffer m_OutPacketLenBuffer;
-
bool m_IsEncrypted;
cAesCfb128Decryptor m_Decryptor;
@@ -297,11 +208,14 @@ protected:
/** Parses Vanilla plugin messages into specific ClientHandle calls.
The message payload is still in the bytebuffer, to be read by this function. */
- void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength);
+ void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, UInt16 a_PayloadLength);
/** Sends the data to the client, encrypting them if needed. */
virtual void SendData(const char * a_Data, size_t a_Size) override;
+ /** Sends the packet to the client. Called by the cPacketizer's destructor. */
+ virtual void SendPacket(cPacketizer & a_Packet) override;
+
void SendCompass(const cWorld & a_World);
/** Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data */
@@ -312,6 +226,24 @@ protected:
void StartEncryption(const Byte * a_Key);
+ /** Converts the BlockFace received by the protocol into eBlockFace constants.
+ If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */
+ eBlockFace FaceIntToBlockFace(Int8 a_FaceInt);
+
+ /** Writes the item data into a packet. */
+ void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item);
+
+ /** Writes the metadata for the specified entity, not including the terminating 0x7f. */
+ void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity);
+
+ /** Writes the mob-specific metadata for the specified mob */
+ void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob);
+
+ /** Writes the entity properties for the specified entity, including the Count field. */
+ void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity);
+
+ /** Writes the block entity data for the specified block entity into the packet. */
+ void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity);
} ;
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index 22280f800..a1ca25200 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -13,6 +13,7 @@ Implements the 1.8.x protocol classes:
#include "Protocol18x.h"
#include "ChunkDataSerializer.h"
#include "PolarSSL++/Sha1Checksum.h"
+#include "Packetizer.h"
#include "../ClientHandle.h"
#include "../Root.h"
@@ -49,6 +50,13 @@ Implements the 1.8.x protocol classes:
+/** The slot number that the client uses to indicate "outside the window". */
+static const Int16 SLOT_NUM_OUTSIDE = -999;
+
+
+
+
+
#define HANDLE_READ(ByteBuf, Proc, Type, Var) \
Type Var; \
if (!ByteBuf.Proc(Var))\
@@ -98,8 +106,6 @@ cProtocol180::cProtocol180(cClientHandle * a_Client, const AString & a_ServerAdd
m_ServerPort(a_ServerPort),
m_State(a_State),
m_ReceivedData(32 KiB),
- m_OutPacketBuffer(64 KiB),
- m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt
m_IsEncrypted(false),
m_LastSentDimension(dimNotSet)
{
@@ -155,8 +161,8 @@ void cProtocol180::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteInt((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt32((a_Vehicle != nullptr) ? a_Vehicle->GetUniqueID() : 0);
Pkt.WriteBool(false);
}
@@ -169,24 +175,24 @@ void cProtocol180::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x24); // Block Action packet
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
- Pkt.WriteByte(a_Byte1);
- Pkt.WriteByte(a_Byte2);
- Pkt.WriteVarInt(a_BlockType);
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WriteBEInt8(a_Byte1);
+ Pkt.WriteBEInt8(a_Byte2);
+ Pkt.WriteVarInt32(a_BlockType);
}
-void cProtocol180::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
+void cProtocol180::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
- Pkt.WriteVarInt(a_EntityID);
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
- Pkt.WriteChar(a_Stage);
+ Pkt.WriteVarInt32(a_EntityID);
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WriteBEInt8(a_Stage);
}
@@ -198,8 +204,8 @@ void cProtocol180::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x23); // Block Change packet
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
- Pkt.WriteVarInt(((UInt32)a_BlockType << 4) | ((UInt32)a_BlockMeta & 15));
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WriteVarInt32(((UInt32)a_BlockType << 4) | ((UInt32)a_BlockMeta & 15));
}
@@ -211,14 +217,14 @@ void cProtocol180::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
- Pkt.WriteInt(a_ChunkX);
- Pkt.WriteInt(a_ChunkZ);
- Pkt.WriteVarInt((UInt32)a_Changes.size());
+ Pkt.WriteBEInt32(a_ChunkX);
+ Pkt.WriteBEInt32(a_ChunkZ);
+ Pkt.WriteVarInt32((UInt32)a_Changes.size());
for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
{
- short Coords = (short) (itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12));
- Pkt.WriteShort(Coords);
- Pkt.WriteVarInt((itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF));
+ Int16 Coords = static_cast<Int16>(itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12));
+ Pkt.WriteBEInt16(Coords);
+ Pkt.WriteVarInt32((itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF));
} // for itr - a_Changes[]
}
@@ -232,7 +238,7 @@ void cProtocol180::SendChat(const AString & a_Message)
cPacketizer Pkt(*this, 0x02); // Chat Message packet
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
- Pkt.WriteChar(0);
+ Pkt.WriteBEInt8(0);
}
@@ -249,7 +255,7 @@ void cProtocol180::SendChat(const cCompositeChat & a_Message)
// Send the message to the client:
cPacketizer Pkt(*this, 0x02);
Pkt.WriteString(a_Message.CreateJsonString(ShouldUseChatPrefixes));
- Pkt.WriteChar(0);
+ Pkt.WriteBEInt8(0);
}
@@ -277,8 +283,8 @@ void cProtocol180::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0d); // Collect Item packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteVarInt(a_Player.GetUniqueID());
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(a_Player.GetUniqueID());
}
@@ -290,8 +296,8 @@ void cProtocol180::SendDestroyEntity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
- Pkt.WriteVarInt(1);
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
}
@@ -328,7 +334,7 @@ void cProtocol180::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
}
@@ -340,10 +346,10 @@ void cProtocol180::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1D); // Entity Effect packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(a_EffectID);
- Pkt.WriteByte(a_Amplifier);
- Pkt.WriteVarInt((UInt32)a_Duration);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID));
+ Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier));
+ Pkt.WriteVarInt32((UInt32)a_Duration);
Pkt.WriteBool(false); // Hide particles
}
@@ -356,9 +362,9 @@ void cProtocol180::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
- Pkt.WriteVarInt((UInt32)a_Entity.GetUniqueID());
- Pkt.WriteShort(a_SlotNum);
- Pkt.WriteItem(a_Item);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt16(a_SlotNum);
+ WriteItem(Pkt, a_Item);
}
@@ -370,7 +376,7 @@ void cProtocol180::SendEntityHeadLook(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
- Pkt.WriteVarInt((UInt32)a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
}
@@ -383,7 +389,7 @@ void cProtocol180::SendEntityLook(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x16); // Entity Look packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetYaw());
Pkt.WriteByteAngle(a_Entity.GetPitch());
Pkt.WriteBool(a_Entity.IsOnGround());
@@ -398,9 +404,9 @@ void cProtocol180::SendEntityMetadata(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteEntityMetadata(a_Entity);
- Pkt.WriteByte(0x7f); // The termination byte
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ WriteEntityMetadata(Pkt, a_Entity);
+ Pkt.WriteBEUInt8(0x7f); // The termination byte
}
@@ -412,8 +418,8 @@ void cProtocol180::SendEntityProperties(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x20); // Entity Properties packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteEntityProperties(a_Entity);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ WriteEntityProperties(Pkt, a_Entity);
}
@@ -425,10 +431,10 @@ void cProtocol180::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(a_RelX);
- Pkt.WriteByte(a_RelY);
- Pkt.WriteByte(a_RelZ);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_RelX);
+ Pkt.WriteBEInt8(a_RelY);
+ Pkt.WriteBEInt8(a_RelZ);
Pkt.WriteBool(a_Entity.IsOnGround());
}
@@ -441,10 +447,10 @@ void cProtocol180::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(a_RelX);
- Pkt.WriteByte(a_RelY);
- Pkt.WriteByte(a_RelZ);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_RelX);
+ Pkt.WriteBEInt8(a_RelY);
+ Pkt.WriteBEInt8(a_RelZ);
Pkt.WriteByteAngle(a_Entity.GetYaw());
Pkt.WriteByteAngle(a_Entity.GetPitch());
Pkt.WriteBool(a_Entity.IsOnGround());
@@ -459,8 +465,8 @@ void cProtocol180::SendEntityStatus(const cEntity & a_Entity, char a_Status)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1a); // Entity Status packet
- Pkt.WriteInt(a_Entity.GetUniqueID());
- Pkt.WriteChar(a_Status);
+ Pkt.WriteBEUInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_Status);
}
@@ -472,11 +478,11 @@ void cProtocol180::SendEntityVelocity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
- Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedZ() * 400));
}
@@ -488,20 +494,20 @@ void cProtocol180::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x27); // Explosion packet
- Pkt.WriteFloat((float)a_BlockX);
- Pkt.WriteFloat((float)a_BlockY);
- Pkt.WriteFloat((float)a_BlockZ);
- Pkt.WriteFloat((float)a_Radius);
- Pkt.WriteInt((int)a_BlocksAffected.size());
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockX));
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockY));
+ Pkt.WriteBEFloat(static_cast<float>(a_BlockZ));
+ Pkt.WriteBEFloat(static_cast<float>(a_Radius));
+ Pkt.WriteBEUInt32(static_cast<UInt32>(a_BlocksAffected.size()));
for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr)
{
- Pkt.WriteChar((char)itr->x);
- Pkt.WriteChar((char)itr->y);
- Pkt.WriteChar((char)itr->z);
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->x));
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->y));
+ Pkt.WriteBEInt8(static_cast<Int8>(itr->z));
} // for itr - a_BlockAffected[]
- Pkt.WriteFloat((float)a_PlayerMotion.x);
- Pkt.WriteFloat((float)a_PlayerMotion.y);
- Pkt.WriteFloat((float)a_PlayerMotion.z);
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.x));
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.y));
+ Pkt.WriteBEFloat(static_cast<float>(a_PlayerMotion.z));
}
@@ -513,8 +519,8 @@ void cProtocol180::SendGameMode(eGameMode a_GameMode)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
- Pkt.WriteByte(3); // Reason: Change game mode
- Pkt.WriteFloat((float)a_GameMode);
+ Pkt.WriteBEUInt8(3); // Reason: Change game mode
+ Pkt.WriteBEFloat(static_cast<float>(a_GameMode)); // The protocol really represents the value with a float!
}
@@ -527,9 +533,9 @@ void cProtocol180::SendHealth(void)
cPacketizer Pkt(*this, 0x06); // Update Health packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteFloat((float)Player->GetHealth());
- Pkt.WriteVarInt((UInt32)Player->GetFoodLevel());
- Pkt.WriteFloat((float)Player->GetFoodSaturationLevel());
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth()));
+ Pkt.WriteVarInt32((UInt32)Player->GetFoodLevel());
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel()));
}
@@ -541,9 +547,9 @@ void cProtocol180::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2f); // Set Slot packet
- Pkt.WriteChar(a_WindowID);
- Pkt.WriteShort(a_SlotNum);
- Pkt.WriteItem(a_Item);
+ Pkt.WriteBEInt8(a_WindowID);
+ Pkt.WriteBEInt16(a_SlotNum);
+ WriteItem(Pkt, a_Item);
}
@@ -560,7 +566,7 @@ void cProtocol180::SendKeepAlive(int a_PingID)
}
cPacketizer Pkt(*this, 0x00); // Keep Alive packet
- Pkt.WriteVarInt(a_PingID);
+ Pkt.WriteVarInt32(a_PingID);
}
@@ -573,11 +579,11 @@ void cProtocol180::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
{
cServer * Server = cRoot::Get()->GetServer();
cPacketizer Pkt(*this, 0x01); // Join Game packet
- Pkt.WriteInt(a_Player.GetUniqueID());
- 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(Server->GetMaxPlayers());
+ Pkt.WriteBEUInt32(a_Player.GetUniqueID());
+ Pkt.WriteBEUInt8((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4
+ Pkt.WriteBEInt8((char)a_World.GetDimension());
+ Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteBEUInt8(Server->GetMaxPlayers());
Pkt.WriteString("default"); // Level type - wtf?
Pkt.WriteBool(false); // Reduced Debug Info - wtf?
}
@@ -586,13 +592,13 @@ void cProtocol180::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
// Send the spawn position:
{
cPacketizer Pkt(*this, 0x05); // Spawn Position packet
- Pkt.WritePosition((int)a_World.GetSpawnX(), (int)a_World.GetSpawnY(), (int)a_World.GetSpawnZ());
+ Pkt.WritePosition64((int)a_World.GetSpawnX(), (int)a_World.GetSpawnY(), (int)a_World.GetSpawnZ());
}
// Send the server difficulty:
{
cPacketizer Pkt(*this, 0x41);
- Pkt.WriteChar(1);
+ Pkt.WriteBEInt8(1);
}
// Send player abilities:
@@ -609,7 +615,7 @@ void cProtocol180::SendLoginSuccess(void)
// Enable compression:
{
cPacketizer Pkt(*this, 0x03); // Set compression packet
- Pkt.WriteVarInt(256);
+ Pkt.WriteVarInt32(256);
}
m_State = 3; // State = Game
@@ -632,19 +638,11 @@ void cProtocol180::SendPaintingSpawn(const cPainting & a_Painting)
double PosY = a_Painting.GetPosY();
double PosZ = a_Painting.GetPosZ();
- switch (a_Painting.GetDirection())
- {
- case 0: PosZ += 1; break;
- case 1: PosX -= 1; break;
- case 2: PosZ -= 1; break;
- case 3: PosX += 1; break;
- }
-
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
- Pkt.WriteVarInt(a_Painting.GetUniqueID());
+ Pkt.WriteVarInt32(a_Painting.GetUniqueID());
Pkt.WriteString(a_Painting.GetName().c_str());
- Pkt.WritePosition((int)PosX, (int)PosY, (int)PosZ);
- Pkt.WriteChar(a_Painting.GetDirection());
+ Pkt.WritePosition64((int)PosX, (int)PosY, (int)PosZ);
+ Pkt.WriteBEInt8(a_Painting.GetProtocolFacing());
}
@@ -656,19 +654,19 @@ void cProtocol180::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x34);
- Pkt.WriteVarInt(a_ID);
- Pkt.WriteByte(m_Scale);
+ Pkt.WriteVarInt32(a_ID);
+ Pkt.WriteBEUInt8(m_Scale);
- Pkt.WriteVarInt(0);
- Pkt.WriteByte(1);
- Pkt.WriteByte(a_Length);
- Pkt.WriteByte(a_X);
- Pkt.WriteByte(a_Y);
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteBEUInt8(1);
+ Pkt.WriteBEUInt8(a_Length);
+ Pkt.WriteBEUInt8(a_X);
+ Pkt.WriteBEUInt8(a_Y);
- Pkt.WriteVarInt(a_Length);
+ Pkt.WriteVarInt32(a_Length);
for (unsigned int i = 0; i < a_Length; ++i)
{
- Pkt.WriteByte(a_Colors[i]);
+ Pkt.WriteBEUInt8(a_Colors[i]);
}
}
@@ -681,18 +679,18 @@ void cProtocol180::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x34);
- Pkt.WriteVarInt(a_ID);
- Pkt.WriteByte(m_Scale);
- Pkt.WriteVarInt(a_Decorators.size());
+ Pkt.WriteVarInt32(a_ID);
+ Pkt.WriteBEUInt8(m_Scale);
+ Pkt.WriteVarInt32(a_Decorators.size());
for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it)
{
- Pkt.WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf));
- Pkt.WriteByte(it->GetPixelX());
- Pkt.WriteByte(it->GetPixelZ());
+ Pkt.WriteBEUInt8((it->GetType() << 4) | (it->GetRot() & 0xf));
+ Pkt.WriteBEUInt8(it->GetPixelX());
+ Pkt.WriteBEUInt8(it->GetPixelZ());
}
- Pkt.WriteByte(0);
+ Pkt.WriteBEUInt8(0);
}
@@ -717,22 +715,22 @@ void cProtocol180::SendPickupSpawn(const cPickup & a_Pickup)
{
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
- Pkt.WriteVarInt(a_Pickup.GetUniqueID());
- Pkt.WriteByte(2); // Type = Pickup
+ Pkt.WriteVarInt32(a_Pickup.GetUniqueID());
+ Pkt.WriteBEUInt8(2); // Type = Pickup
Pkt.WriteFPInt(a_Pickup.GetPosX());
Pkt.WriteFPInt(a_Pickup.GetPosY());
Pkt.WriteFPInt(a_Pickup.GetPosZ());
Pkt.WriteByteAngle(a_Pickup.GetYaw());
Pkt.WriteByteAngle(a_Pickup.GetPitch());
- Pkt.WriteInt(0); // No object data
+ Pkt.WriteBEInt32(0); // No object data
}
{
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
- Pkt.WriteVarInt(a_Pickup.GetUniqueID());
- Pkt.WriteByte((0x05 << 5) | 10); // Slot type + index 10
- Pkt.WriteItem(a_Pickup.GetItem());
- Pkt.WriteByte(0x7f); // End of metadata
+ Pkt.WriteVarInt32(a_Pickup.GetUniqueID());
+ Pkt.WriteBEUInt8((0x05 << 5) | 10); // Slot type + index 10
+ WriteItem(Pkt, a_Pickup.GetItem());
+ Pkt.WriteBEUInt8(0x7f); // End of metadata
}
}
@@ -760,9 +758,9 @@ void cProtocol180::SendPlayerAbilities(void)
{
Flags |= 0x04;
}
- Pkt.WriteByte(Flags);
- Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed()));
- Pkt.WriteFloat((float)(0.1 * Player->GetNormalMaxSpeed()));
+ Pkt.WriteBEUInt8(Flags);
+ Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed()));
+ Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed()));
}
@@ -774,8 +772,8 @@ void cProtocol180::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0b); // Animation packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteChar(a_Animation);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEInt8(a_Animation);
}
@@ -788,16 +786,16 @@ void cProtocol180::SendParticleEffect(const AString & a_ParticleName, float a_Sr
int ParticleID = GetParticleID(a_ParticleName);
cPacketizer Pkt(*this, 0x2A);
- Pkt.WriteInt(ParticleID);
+ Pkt.WriteBEInt32(ParticleID);
Pkt.WriteBool(false);
- Pkt.WriteFloat(a_SrcX);
- Pkt.WriteFloat(a_SrcY);
- Pkt.WriteFloat(a_SrcZ);
- Pkt.WriteFloat(a_OffsetX);
- Pkt.WriteFloat(a_OffsetY);
- Pkt.WriteFloat(a_OffsetZ);
- Pkt.WriteFloat(a_ParticleData);
- Pkt.WriteInt(a_ParticleAmount);
+ Pkt.WriteBEFloat(a_SrcX);
+ Pkt.WriteBEFloat(a_SrcY);
+ Pkt.WriteBEFloat(a_SrcZ);
+ Pkt.WriteBEFloat(a_OffsetX);
+ Pkt.WriteBEFloat(a_OffsetY);
+ Pkt.WriteBEFloat(a_OffsetZ);
+ Pkt.WriteBEFloat(a_ParticleData);
+ Pkt.WriteBEInt32(a_ParticleAmount);
}
@@ -809,13 +807,13 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteVarInt(0);
- Pkt.WriteVarInt(1);
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteString(a_Player.GetPlayerListName());
const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
- Pkt.WriteVarInt(Properties.size());
+ Pkt.WriteVarInt32(Properties.size());
for (Json::Value::iterator itr = Properties.begin(), end = Properties.end(); itr != end; ++itr)
{
Pkt.WriteString(((Json::Value)*itr).get("name", "").asString());
@@ -832,8 +830,8 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player)
}
}
- Pkt.WriteVarInt((UInt32)a_Player.GetGameMode());
- Pkt.WriteVarInt((UInt32)a_Player.GetClientHandle()->GetPing());
+ Pkt.WriteVarInt32((UInt32)a_Player.GetGameMode());
+ Pkt.WriteVarInt32((UInt32)a_Player.GetClientHandle()->GetPing());
Pkt.WriteBool(false);
}
@@ -846,8 +844,8 @@ void cProtocol180::SendPlayerListRemovePlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteVarInt(4);
- Pkt.WriteVarInt(1);
+ Pkt.WriteVarInt32(4);
+ Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
}
@@ -860,10 +858,10 @@ void cProtocol180::SendPlayerListUpdateGameMode(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteVarInt(1);
- Pkt.WriteVarInt(1);
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
- Pkt.WriteVarInt((UInt32)a_Player.GetGameMode());
+ Pkt.WriteVarInt32((UInt32)a_Player.GetGameMode());
}
@@ -878,10 +876,10 @@ void cProtocol180::SendPlayerListUpdatePing(const cPlayer & a_Player)
if (ClientHandle != nullptr)
{
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteVarInt(2);
- Pkt.WriteVarInt(1);
+ Pkt.WriteVarInt32(2);
+ Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
- Pkt.WriteVarInt(static_cast<UInt32>(ClientHandle->GetPing()));
+ Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing()));
}
}
@@ -894,8 +892,8 @@ void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, con
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteVarInt(3);
- Pkt.WriteVarInt(1);
+ Pkt.WriteVarInt32(3);
+ Pkt.WriteVarInt32(1);
Pkt.WriteUUID(a_Player.GetUUID());
if (a_CustomName.empty())
@@ -919,22 +917,22 @@ void cProtocol180::SendPlayerMaxSpeed(void)
cPacketizer Pkt(*this, 0x20); // Entity Properties
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteVarInt(Player->GetUniqueID());
- Pkt.WriteInt(1); // Count
+ Pkt.WriteVarInt32(Player->GetUniqueID());
+ Pkt.WriteBEInt32(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
- Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed());
+ Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
- Pkt.WriteVarInt(1); // Modifier count
- Pkt.WriteInt64(0x662a6b8dda3e4c1c);
- Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier
- Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
- Pkt.WriteByte(2);
+ Pkt.WriteVarInt32(1); // Modifier count
+ Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
+ Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
+ Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
+ Pkt.WriteBEUInt8(2);
}
else
{
- Pkt.WriteVarInt(0); // Modifier count
+ Pkt.WriteVarInt32(0); // Modifier count
}
}
@@ -948,15 +946,15 @@ void cProtocol180::SendPlayerMoveLook(void)
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteDouble(Player->GetPosX());
+ Pkt.WriteBEDouble(Player->GetPosX());
// The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
- Pkt.WriteDouble(Player->GetPosY() + 0.001);
+ Pkt.WriteBEDouble(Player->GetPosY() + 0.001);
- Pkt.WriteDouble(Player->GetPosZ());
- Pkt.WriteFloat((float)Player->GetYaw());
- Pkt.WriteFloat((float)Player->GetPitch());
- Pkt.WriteByte(0);
+ Pkt.WriteBEDouble(Player->GetPosZ());
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw()));
+ Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch()));
+ Pkt.WriteBEUInt8(0);
}
@@ -977,7 +975,7 @@ void cProtocol180::SendPlayerSpawn(const cPlayer & a_Player)
{
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
- Pkt.WriteVarInt(a_Player.GetUniqueID());
+ Pkt.WriteVarInt32(a_Player.GetUniqueID());
Pkt.WriteUUID(cMojangAPI::MakeUUIDShort(a_Player.GetUUID()));
Pkt.WriteFPInt(a_Player.GetPosX());
Pkt.WriteFPInt(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
@@ -985,12 +983,12 @@ void cProtocol180::SendPlayerSpawn(const cPlayer & a_Player)
Pkt.WriteByteAngle(a_Player.GetYaw());
Pkt.WriteByteAngle(a_Player.GetPitch());
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
- Pkt.WriteShort(ItemType);
- Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
- Pkt.WriteFloat((float)a_Player.GetHealth());
- Pkt.WriteByte((4 << 5 | (2 & 0x1F)) & 0xFF);
+ Pkt.WriteBEInt16(ItemType);
+ Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6
+ Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth()));
+ Pkt.WriteBEUInt8((4 << 5 | (2 & 0x1F)) & 0xFF);
Pkt.WriteString(a_Player.GetName());
- Pkt.WriteByte(0x7f); // Metadata: end
+ Pkt.WriteBEUInt8(0x7f); // Metadata: end
}
@@ -1015,8 +1013,8 @@ void cProtocol180::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1e);
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(a_EffectID);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(a_EffectID);
}
@@ -1033,9 +1031,9 @@ void cProtocol180::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimens
cPacketizer Pkt(*this, 0x07); // Respawn packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteInt((int)a_Dimension);
- Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
- Pkt.WriteByte((Byte)Player->GetEffectiveGameMode());
+ Pkt.WriteBEInt32((int)a_Dimension);
+ Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteBEUInt8((Byte)Player->GetEffectiveGameMode());
Pkt.WriteString("default");
m_LastSentDimension = a_Dimension;
}
@@ -1050,9 +1048,9 @@ void cProtocol180::SendExperience(void)
cPacketizer Pkt(*this, 0x1f); // Experience Packet
cPlayer * Player = m_Client->GetPlayer();
- Pkt.WriteFloat(Player->GetXpPercentage());
- Pkt.WriteVarInt((UInt32)Player->GetXpLevel());
- Pkt.WriteVarInt((UInt32)Player->GetCurrentXp());
+ Pkt.WriteBEFloat(Player->GetXpPercentage());
+ Pkt.WriteVarInt32((UInt32)Player->GetXpLevel());
+ Pkt.WriteVarInt32((UInt32)Player->GetCurrentXp());
}
@@ -1064,11 +1062,11 @@ void cProtocol180::SendExperienceOrb(const cExpOrb & a_ExpOrb)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x11);
- Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
+ Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID());
Pkt.WriteFPInt(a_ExpOrb.GetPosX());
Pkt.WriteFPInt(a_ExpOrb.GetPosY());
Pkt.WriteFPInt(a_ExpOrb.GetPosZ());
- Pkt.WriteShort(a_ExpOrb.GetReward());
+ Pkt.WriteBEInt16(a_ExpOrb.GetReward());
}
@@ -1081,7 +1079,7 @@ void cProtocol180::SendScoreboardObjective(const AString & a_Name, const AString
cPacketizer Pkt(*this, 0x3b);
Pkt.WriteString(a_Name);
- Pkt.WriteByte(a_Mode);
+ Pkt.WriteBEUInt8(a_Mode);
if ((a_Mode == 0) || (a_Mode == 2))
{
Pkt.WriteString(a_DisplayName);
@@ -1099,12 +1097,12 @@ void cProtocol180::SendScoreUpdate(const AString & a_Objective, const AString &
cPacketizer Pkt(*this, 0x3c);
Pkt.WriteString(a_Player);
- Pkt.WriteByte(a_Mode);
+ Pkt.WriteBEUInt8(a_Mode);
Pkt.WriteString(a_Objective);
if (a_Mode != 1)
{
- Pkt.WriteVarInt((UInt32) a_Score);
+ Pkt.WriteVarInt32((UInt32) a_Score);
}
}
@@ -1117,7 +1115,7 @@ void cProtocol180::SendDisplayObjective(const AString & a_Objective, cScoreboard
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3d);
- Pkt.WriteByte((int) a_Display);
+ Pkt.WriteBEUInt8((int) a_Display);
Pkt.WriteString(a_Objective);
}
@@ -1131,11 +1129,11 @@ void cProtocol180::SendSoundEffect(const AString & a_SoundName, double a_X, doub
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName);
- Pkt.WriteInt((int)(a_X * 8.0));
- Pkt.WriteInt((int)(a_Y * 8.0));
- Pkt.WriteInt((int)(a_Z * 8.0));
- Pkt.WriteFloat(a_Volume);
- Pkt.WriteByte((Byte)(a_Pitch * 63));
+ Pkt.WriteBEInt32((int)(a_X * 8.0));
+ Pkt.WriteBEInt32((int)(a_Y * 8.0));
+ Pkt.WriteBEInt32((int)(a_Z * 8.0));
+ Pkt.WriteBEFloat(a_Volume);
+ Pkt.WriteBEUInt8((Byte)(a_Pitch * 63));
}
@@ -1147,9 +1145,9 @@ void cProtocol180::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x28); // Effect packet
- Pkt.WriteInt(a_EffectID);
- Pkt.WritePosition(a_SrcX, a_SrcY, a_SrcZ);
- Pkt.WriteInt(a_Data);
+ Pkt.WriteBEInt32(a_EffectID);
+ Pkt.WritePosition64(a_SrcX, a_SrcY, a_SrcZ);
+ Pkt.WriteBEInt32(a_Data);
Pkt.WriteBool(false);
}
@@ -1162,17 +1160,17 @@ void cProtocol180::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
- Pkt.WriteVarInt(a_FallingBlock.GetUniqueID());
- Pkt.WriteByte(70); // Falling block
+ Pkt.WriteVarInt32(a_FallingBlock.GetUniqueID());
+ Pkt.WriteBEUInt8(70); // Falling block
Pkt.WriteFPInt(a_FallingBlock.GetPosX());
Pkt.WriteFPInt(a_FallingBlock.GetPosY());
Pkt.WriteFPInt(a_FallingBlock.GetPosZ());
Pkt.WriteByteAngle(a_FallingBlock.GetYaw());
Pkt.WriteByteAngle(a_FallingBlock.GetPitch());
- Pkt.WriteInt(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 12));
- Pkt.WriteShort((short)(a_FallingBlock.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_FallingBlock.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400));
+ Pkt.WriteBEInt32(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 12));
+ Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedX() * 400));
+ Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedY() * 400));
+ Pkt.WriteBEInt16((short)(a_FallingBlock.GetSpeedZ() * 400));
}
@@ -1184,19 +1182,19 @@ void cProtocol180::SendSpawnMob(const cMonster & a_Mob)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
- Pkt.WriteVarInt(a_Mob.GetUniqueID());
- Pkt.WriteByte((Byte)a_Mob.GetMobType());
+ Pkt.WriteVarInt32(a_Mob.GetUniqueID());
+ Pkt.WriteBEUInt8((Byte)a_Mob.GetMobType());
Pkt.WriteFPInt(a_Mob.GetPosX());
Pkt.WriteFPInt(a_Mob.GetPosY());
Pkt.WriteFPInt(a_Mob.GetPosZ());
Pkt.WriteByteAngle(a_Mob.GetPitch());
Pkt.WriteByteAngle(a_Mob.GetHeadYaw());
Pkt.WriteByteAngle(a_Mob.GetYaw());
- Pkt.WriteShort((short)(a_Mob.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_Mob.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_Mob.GetSpeedZ() * 400));
- Pkt.WriteEntityMetadata(a_Mob);
- Pkt.WriteByte(0x7f); // Metadata terminator
+ Pkt.WriteBEInt16((short)(a_Mob.GetSpeedX() * 400));
+ Pkt.WriteBEInt16((short)(a_Mob.GetSpeedY() * 400));
+ Pkt.WriteBEInt16((short)(a_Mob.GetSpeedZ() * 400));
+ WriteEntityMetadata(Pkt, a_Mob);
+ Pkt.WriteBEUInt8(0x7f); // Metadata terminator
}
@@ -1215,19 +1213,19 @@ void cProtocol180::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
}
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WriteByte(a_ObjectType);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteBEUInt8(a_ObjectType);
Pkt.WriteFPInt(PosX);
Pkt.WriteFPInt(a_Entity.GetPosY());
Pkt.WriteFPInt(PosZ);
Pkt.WriteByteAngle(a_Entity.GetPitch());
Pkt.WriteByteAngle(Yaw);
- Pkt.WriteInt(a_ObjectData);
+ Pkt.WriteBEInt32(a_ObjectData);
if (a_ObjectData != 0)
{
- Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteBEInt16((short)(a_Entity.GetSpeedZ() * 400));
}
}
@@ -1240,19 +1238,19 @@ void cProtocol180::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
- Pkt.WriteVarInt(a_Vehicle.GetUniqueID());
- Pkt.WriteByte(a_VehicleType);
+ Pkt.WriteVarInt32(a_Vehicle.GetUniqueID());
+ Pkt.WriteBEUInt8(a_VehicleType);
Pkt.WriteFPInt(a_Vehicle.GetPosX());
Pkt.WriteFPInt(a_Vehicle.GetPosY());
Pkt.WriteFPInt(a_Vehicle.GetPosZ());
Pkt.WriteByteAngle(a_Vehicle.GetPitch());
Pkt.WriteByteAngle(a_Vehicle.GetYaw());
- Pkt.WriteInt(a_VehicleSubType);
+ Pkt.WriteBEInt32(a_VehicleSubType);
if (a_VehicleSubType != 0)
{
- Pkt.WriteShort((short)(a_Vehicle.GetSpeedX() * 400));
- Pkt.WriteShort((short)(a_Vehicle.GetSpeedY() * 400));
- Pkt.WriteShort((short)(a_Vehicle.GetSpeedZ() * 400));
+ Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedX() * 400));
+ Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedY() * 400));
+ Pkt.WriteBEInt16((short)(a_Vehicle.GetSpeedZ() * 400));
}
}
@@ -1265,7 +1263,7 @@ void cProtocol180::SendStatistics(const cStatManager & a_Manager)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x37);
- Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
+ Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
for (size_t i = 0; i < (size_t)statCount; ++i)
{
@@ -1273,7 +1271,7 @@ void cProtocol180::SendStatistics(const cStatManager & a_Manager)
const AString & StatName = cStatInfo::GetName((eStatistic) i);
Pkt.WriteString(StatName);
- Pkt.WriteVarInt(Value);
+ Pkt.WriteVarInt32(Value);
}
}
@@ -1286,7 +1284,7 @@ void cProtocol180::SendTabCompletionResults(const AStringVector & a_Results)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
- Pkt.WriteVarInt((int)a_Results.size());
+ Pkt.WriteVarInt32((int)a_Results.size());
for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
{
@@ -1303,7 +1301,7 @@ void cProtocol180::SendTeleportEntity(const cEntity & a_Entity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x18);
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteFPInt(a_Entity.GetPosX());
Pkt.WriteFPInt(a_Entity.GetPosY());
Pkt.WriteFPInt(a_Entity.GetPosZ());
@@ -1321,8 +1319,8 @@ void cProtocol180::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
- Pkt.WriteVarInt(0); // EntityID = 0, always
- Pkt.WriteByte(1); // Type = Thunderbolt
+ Pkt.WriteVarInt32(0); // EntityID = 0, always
+ Pkt.WriteBEUInt8(1); // Type = Thunderbolt
Pkt.WriteFPInt(a_BlockX);
Pkt.WriteFPInt(a_BlockY);
Pkt.WriteFPInt(a_BlockZ);
@@ -1342,8 +1340,8 @@ void cProtocol180::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_Do
}
cPacketizer Pkt(*this, 0x03);
- Pkt.WriteInt64(a_WorldAge);
- Pkt.WriteInt64(a_TimeOfDay);
+ Pkt.WriteBEInt64(a_WorldAge);
+ Pkt.WriteBEInt64(a_TimeOfDay);
}
@@ -1355,11 +1353,11 @@ void cProtocol180::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
- Pkt.WriteInt(a_ChunkX);
- Pkt.WriteInt(a_ChunkZ);
+ Pkt.WriteBEInt32(a_ChunkX);
+ Pkt.WriteBEInt32(a_ChunkZ);
Pkt.WriteBool(true);
- Pkt.WriteShort(0); // Primary bitmap
- Pkt.WriteVarInt(0); // Data size
+ Pkt.WriteBEInt16(0); // Primary bitmap
+ Pkt.WriteVarInt32(0); // Data size
}
@@ -1370,7 +1368,7 @@ void cProtocol180::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x35); // Update tile entity packet
- Pkt.WritePosition(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ());
+ Pkt.WritePosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ());
Byte Action = 0;
switch (a_BlockEntity.GetBlockType())
@@ -1382,9 +1380,9 @@ void cProtocol180::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
}
- Pkt.WriteByte(Action);
+ Pkt.WriteBEUInt8(Action);
- Pkt.WriteBlockEntity(a_BlockEntity);
+ WriteBlockEntity(Pkt, a_BlockEntity);
}
@@ -1396,7 +1394,7 @@ void cProtocol180::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x33);
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
Json::StyledWriter JsonWriter;
AString Lines[] = { a_Line1, a_Line2, a_Line3, a_Line4 };
@@ -1417,8 +1415,8 @@ void cProtocol180::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0a);
- Pkt.WriteVarInt(a_Entity.GetUniqueID());
- Pkt.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ);
}
@@ -1431,8 +1429,8 @@ void cProtocol180::SendWeather(eWeather a_Weather)
{
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
- Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
- Pkt.WriteFloat(0); // Unused for weather
+ Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
+ Pkt.WriteBEFloat(0); // Unused for weather
}
// TODO: Fade effect, somehow
@@ -1447,13 +1445,13 @@ void cProtocol180::SendWholeInventory(const cWindow & a_Window)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x30); // Window Items packet
- Pkt.WriteChar(a_Window.GetWindowID());
- Pkt.WriteShort(a_Window.GetNumSlots());
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
+ Pkt.WriteBEInt16(a_Window.GetNumSlots());
cItems Slots;
a_Window.GetSlots(*(m_Client->GetPlayer()), Slots);
for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr)
{
- Pkt.WriteItem(*itr);
+ WriteItem(Pkt, *itr);
} // for itr - Slots[]
}
@@ -1466,7 +1464,7 @@ void cProtocol180::SendWindowClose(const cWindow & a_Window)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e);
- Pkt.WriteChar(a_Window.GetWindowID());
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
}
@@ -1484,7 +1482,7 @@ void cProtocol180::SendWindowOpen(const cWindow & a_Window)
}
cPacketizer Pkt(*this, 0x2d);
- Pkt.WriteChar(a_Window.GetWindowID());
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
Pkt.WriteString(a_Window.GetWindowTypeName());
Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Window.GetWindowTitle().c_str()));
@@ -1494,19 +1492,19 @@ void cProtocol180::SendWindowOpen(const cWindow & a_Window)
case cWindow::wtEnchantment:
case cWindow::wtAnvil:
{
- Pkt.WriteChar(0);
+ Pkt.WriteBEInt8(0);
break;
}
default:
{
- Pkt.WriteChar(a_Window.GetNumNonInventorySlots());
+ Pkt.WriteBEInt8(a_Window.GetNumNonInventorySlots());
break;
}
}
if (a_Window.GetWindowType() == cWindow::wtAnimalChest)
{
- Pkt.WriteInt(0); // TODO: The animal's EntityID
+ Pkt.WriteBEInt32(0); // TODO: The animal's EntityID
}
}
@@ -1519,9 +1517,9 @@ void cProtocol180::SendWindowProperty(const cWindow & a_Window, short a_Property
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x31); // Window Property packet
- Pkt.WriteChar(a_Window.GetWindowID());
- Pkt.WriteShort(a_Property);
- Pkt.WriteShort(a_Value);
+ Pkt.WriteBEInt8(a_Window.GetWindowID());
+ Pkt.WriteBEInt16(a_Property);
+ Pkt.WriteBEInt16(a_Value);
}
@@ -1540,7 +1538,10 @@ bool cProtocol180::CompressPacket(const AString & a_Packet, AString & a_Compress
return false;
}
- int Status = compress2((Bytef*)CompressedData, &CompressedSize, (const Bytef*)a_Packet.data(), a_Packet.size(), Z_DEFAULT_COMPRESSION);
+ int Status = compress2(
+ reinterpret_cast<Bytef *>(CompressedData), &CompressedSize,
+ reinterpret_cast<const Bytef *>(a_Packet.data()), a_Packet.size(), Z_DEFAULT_COMPRESSION
+ );
if (Status != Z_OK)
{
return false;
@@ -1548,12 +1549,12 @@ bool cProtocol180::CompressPacket(const AString & a_Packet, AString & a_Compress
AString LengthData;
cByteBuffer Buffer(20);
- Buffer.WriteVarInt((UInt32)a_Packet.size());
+ Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size()));
Buffer.ReadAll(LengthData);
Buffer.CommitRead();
- Buffer.WriteVarInt(CompressedSize + LengthData.size());
- Buffer.WriteVarInt(a_Packet.size());
+ Buffer.WriteVarInt32(CompressedSize + LengthData.size());
+ Buffer.WriteVarInt32(static_cast<UInt32>(a_Packet.size()));
Buffer.ReadAll(LengthData);
Buffer.CommitRead();
@@ -1951,7 +1952,7 @@ void cProtocol180::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp);
cPacketizer Pkt(*this, 0x01); // Ping packet
- Pkt.WriteInt64(Timestamp);
+ Pkt.WriteBEInt64(Timestamp);
}
@@ -2088,10 +2089,10 @@ void cProtocol180::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
cPacketizer Pkt(*this, 0x01);
Pkt.WriteString(Server->GetServerID());
const AString & PubKeyDer = Server->GetPublicKeyDER();
- Pkt.WriteVarInt((short)PubKeyDer.size());
+ Pkt.WriteVarInt32((short)PubKeyDer.size());
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
- Pkt.WriteVarInt(4);
- Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
+ Pkt.WriteVarInt32(4);
+ Pkt.WriteBEInt32((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
m_Client->SetUsername(Username);
return;
}
@@ -2105,9 +2106,7 @@ void cProtocol180::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, EntityID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Animation);
- m_Client->HandleAnimation(Animation);
+ m_Client->HandleAnimation(1); // Packet exists solely for arm-swing notification
}
@@ -2116,16 +2115,16 @@ void cProtocol180::HandlePacketAnimation(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Status);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
int BlockX, BlockY, BlockZ;
- if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ))
+ if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
{
return;
}
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face);
- m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), Status);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
+ m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), Status);
}
@@ -2135,24 +2134,20 @@ void cProtocol180::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer)
{
int BlockX, BlockY, BlockZ;
- if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ))
+ if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
{
return;
}
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face);
- if (Face == 255)
- {
- Face = 0;
- }
+ HANDLE_READ(a_ByteBuffer, ReadBEInt8, Int8, Face);
cItem Item;
ReadItem(a_ByteBuffer, Item, 3);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorX);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorY);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorZ);
- m_Client->HandleRightClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorX);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorY);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, CursorZ);
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
}
@@ -2172,10 +2167,10 @@ void cProtocol180::HandlePacketChatMessage(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ViewDistance);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatFlags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags);
HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors);
- HANDLE_READ(a_ByteBuffer, ReadChar, char, SkinFlags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinFlags);
m_Client->SetLocale(Locale);
m_Client->SetViewDistance(ViewDistance);
@@ -2188,7 +2183,7 @@ void cProtocol180::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, ActionID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID);
switch (ActionID)
{
case 0:
@@ -2220,13 +2215,13 @@ void cProtocol180::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
cItem Item;
if (!ReadItem(a_ByteBuffer, Item))
{
return;
}
- m_Client->HandleCreativeInventory(SlotNum, Item);
+ m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutside : caLeftClick);
}
@@ -2235,9 +2230,9 @@ void cProtocol180::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffe
void cProtocol180::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID);
- HANDLE_READ(a_ByteBuffer, ReadChar, char, Action);
- HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, JumpBoost);
switch (Action)
{
@@ -2256,7 +2251,7 @@ void cProtocol180::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, KeepAliveID);
- m_Client->HandleKeepAlive((int)KeepAliveID);
+ m_Client->HandleKeepAlive(static_cast<int>(KeepAliveID));
}
@@ -2275,10 +2270,11 @@ void cProtocol180::HandlePacketPlayer(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketPlayerAbilities(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Flags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed);
+ // COnvert the bitfield into individual boolean flags:
bool IsFlying = false, CanFly = false;
if ((Flags & 2) != 0)
{
@@ -2369,7 +2365,7 @@ void cProtocol180::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
m_Client->HandleSlotSelected(SlotNum);
}
@@ -2381,7 +2377,7 @@ void cProtocol180::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Forward);
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways);
- HANDLE_READ(a_ByteBuffer, ReadChar, char, Flags);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags);
if ((Flags & 0x2) != 0)
{
@@ -2400,7 +2396,7 @@ void cProtocol180::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Text);
- HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition);
+ HANDLE_READ(a_ByteBuffer, ReadBool, bool, HasPosition);
if (HasPosition)
{
@@ -2417,7 +2413,7 @@ void cProtocol180::HandlePacketTabComplete(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketUpdateSign(cByteBuffer & a_ByteBuffer)
{
int BlockX, BlockY, BlockZ;
- if (!a_ByteBuffer.ReadPosition(BlockX, BlockY, BlockZ))
+ if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ))
{
return;
}
@@ -2445,12 +2441,12 @@ void cProtocol180::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
{
case 0:
{
- m_Client->HandleUseEntity((int)EntityID, false);
+ m_Client->HandleUseEntity(EntityID, false);
break;
}
case 1:
{
- m_Client->HandleUseEntity((int)EntityID, true);
+ m_Client->HandleUseEntity(EntityID, true);
break;
}
case 2:
@@ -2476,8 +2472,8 @@ void cProtocol180::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment);
m_Client->HandleEnchantItem(WindowID, Enchantment);
}
@@ -2488,11 +2484,11 @@ void cProtocol180::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, SlotNum);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Button);
- HANDLE_READ(a_ByteBuffer, ReadBEShort, short, TransactionID);
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Button);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt16, UInt16, TransactionID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode);
cItem Item;
ReadItem(a_ByteBuffer, Item);
@@ -2500,8 +2496,8 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
eClickAction Action;
switch ((Mode << 8) | Button)
{
- case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break;
- case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break;
+ case 0x0000: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftClick : caLeftClickOutside; break;
+ case 0x0001: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightClick : caRightClickOutside; break;
case 0x0100: Action = caShiftLeftClick; break;
case 0x0101: Action = caShiftRightClick; break;
case 0x0200: Action = caNumber1; break;
@@ -2514,14 +2510,14 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
case 0x0207: Action = caNumber8; break;
case 0x0208: Action = caNumber9; break;
case 0x0300: Action = caMiddleClick; break;
- case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break;
- case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
- case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break;
- case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break;
- case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break;
- case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break;
- case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break;
- case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break;
+ case 0x0400: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutsideHoldNothing : caDropKey; break;
+ case 0x0401: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
+ case 0x0500: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintBegin : caUnknown; break;
+ case 0x0501: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caLeftPaintProgress : caUnknown; break;
+ case 0x0502: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftPaintEnd : caUnknown; break;
+ case 0x0504: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintBegin : caUnknown; break;
+ case 0x0505: Action = (SlotNum != SLOT_NUM_OUTSIDE) ? caRightPaintProgress : caUnknown; break;
+ case 0x0506: Action = (SlotNum == SLOT_NUM_OUTSIDE) ? caRightPaintEnd : caUnknown; break;
case 0x0600: Action = caDblClick; break;
default:
{
@@ -2540,7 +2536,7 @@ void cProtocol180::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer)
void cProtocol180::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer)
{
- HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
m_Client->HandleWindowClose(WindowID);
}
@@ -2552,14 +2548,14 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
{
if (a_Channel == "MC|AdvCdm")
{
- HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode)
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode)
switch (Mode)
{
case 0x00:
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ);
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command);
m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command);
break;
@@ -2567,7 +2563,7 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
default:
{
- m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure);
+ m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %u (0x%02x)", Mode, Mode), mtFailure);
LOG("Unhandled MC|AdvCdm packet mode.");
return;
}
@@ -2584,8 +2580,8 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
else if (a_Channel == "MC|Beacon")
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1);
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2);
m_Client->HandleBeaconSelection(Effect1, Effect2);
return;
}
@@ -2597,7 +2593,7 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
else if (a_Channel == "MC|TrSel")
{
- HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum);
+ HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum);
m_Client->HandleNPCTrade(SlotNum);
return;
}
@@ -2639,7 +2635,7 @@ void cProtocol180::SendData(const char * a_Data, size_t a_Size)
bool cProtocol180::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes)
{
- HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemType);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType);
if (ItemType == -1)
{
// The item is empty, no more data follows
@@ -2648,8 +2644,8 @@ bool cProtocol180::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a
}
a_Item.m_ItemType = ItemType;
- HANDLE_PACKET_READ(a_ByteBuffer, ReadChar, char, ItemCount);
- HANDLE_PACKET_READ(a_ByteBuffer, ReadBEShort, short, ItemDamage);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount);
+ HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage);
a_Item.m_ItemCount = ItemCount;
a_Item.m_ItemDamage = ItemDamage;
if (ItemCount <= 0)
@@ -2765,59 +2761,81 @@ void cProtocol180::StartEncryption(const Byte * a_Key)
+eBlockFace cProtocol180::FaceIntToBlockFace(Int8 a_BlockFace)
+{
+ // Normalize the blockface values returned from the protocol
+ // Anything known gets mapped 1:1, everything else returns BLOCK_FACE_NONE
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_XM: return BLOCK_FACE_XM;
+ case BLOCK_FACE_XP: return BLOCK_FACE_XP;
+ case BLOCK_FACE_YM: return BLOCK_FACE_YM;
+ case BLOCK_FACE_YP: return BLOCK_FACE_YP;
+ case BLOCK_FACE_ZM: return BLOCK_FACE_ZM;
+ case BLOCK_FACE_ZP: return BLOCK_FACE_ZP;
+ default: return BLOCK_FACE_NONE;
+ }
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cProtocol180::cPacketizer:
-cProtocol180::cPacketizer::~cPacketizer()
+void cProtocol180::SendPacket(cPacketizer & a_Pkt)
{
- UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace();
+ UInt32 PacketLen = static_cast<UInt32>(m_OutPacketBuffer.GetUsedSpace());
AString PacketData, CompressedPacket;
- m_Out.ReadAll(PacketData);
- m_Out.CommitRead();
+ m_OutPacketBuffer.ReadAll(PacketData);
+ m_OutPacketBuffer.CommitRead();
- if ((m_Protocol.m_State == 3) && (PacketLen >= 256))
+ if ((m_State == 3) && (PacketLen >= 256))
{
+ // Compress the packet payload:
if (!cProtocol180::CompressPacket(PacketData, CompressedPacket))
{
return;
}
}
- else if (m_Protocol.m_State == 3)
+ else if (m_State == 3)
{
- m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen + 1);
- m_Protocol.m_OutPacketLenBuffer.WriteVarInt(0);
-
+ // The packet is not compressed, indicate this in the packet header:
+ m_OutPacketLenBuffer.WriteVarInt32(PacketLen + 1);
+ m_OutPacketLenBuffer.WriteVarInt32(0);
AString LengthData;
- m_Protocol.m_OutPacketLenBuffer.ReadAll(LengthData);
- m_Protocol.SendData(LengthData.data(), LengthData.size());
+ m_OutPacketLenBuffer.ReadAll(LengthData);
+ SendData(LengthData.data(), LengthData.size());
}
else
{
- m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen);
-
+ // Compression doesn't apply to this state, send raw data:
+ m_OutPacketLenBuffer.WriteVarInt32(PacketLen);
AString LengthData;
- m_Protocol.m_OutPacketLenBuffer.ReadAll(LengthData);
- m_Protocol.SendData(LengthData.data(), LengthData.size());
+ m_OutPacketLenBuffer.ReadAll(LengthData);
+ SendData(LengthData.data(), LengthData.size());
}
+ // Send the packet's payload, either direct or compressed:
if (CompressedPacket.empty())
{
- m_Protocol.m_OutPacketLenBuffer.CommitRead();
- m_Protocol.SendData(PacketData.data(), PacketData.size());
+ m_OutPacketLenBuffer.CommitRead();
+ SendData(PacketData.data(), PacketData.size());
}
else
{
- m_Protocol.SendData(CompressedPacket.data(), CompressedPacket.size());
+ SendData(CompressedPacket.data(), CompressedPacket.size());
}
// Log the comm into logfile:
- if (g_ShouldLogCommOut && m_Protocol.m_CommLogFile.IsOpen())
+ if (g_ShouldLogCommOut && m_CommLogFile.IsOpen())
{
AString Hex;
ASSERT(PacketData.size() > 0);
- CreateHexDump(Hex, PacketData.data() + 1, PacketData.size() - 1, 16);
- m_Protocol.m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload:\n%s\n",
- PacketData[0], PacketData[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str()
+ CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16);
+ m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload (incl. type):\n%s\n",
+ a_Pkt.GetPacketType(), a_Pkt.GetPacketType(), PacketLen, PacketLen, m_State, Hex.c_str()
);
}
}
@@ -2826,30 +2844,7 @@ cProtocol180::cPacketizer::~cPacketizer()
-void cProtocol180::cPacketizer::WriteUUID(const AString & a_UUID)
-{
- if (a_UUID.length() != 32)
- {
- LOGWARNING("Attempt to send a bad uuid (length isn't 32): %s", a_UUID.c_str());
- ASSERT(!"Wrong uuid length!");
- return;
- }
- AString UUID_1 = a_UUID.substr(0, 16);
- AString UUID_2 = a_UUID.substr(16);
-
- Int64 Value_1, Value_2;
- sscanf(UUID_1.c_str(), "%llx", &Value_1);
- sscanf(UUID_2.c_str(), "%llx", &Value_2);
-
- WriteInt64(Value_1);
- WriteInt64(Value_2);
-}
-
-
-
-
-
-void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item)
+void cProtocol180::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item)
{
short ItemType = a_Item.m_ItemType;
ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
@@ -2861,17 +2856,17 @@ void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item)
if (a_Item.IsEmpty())
{
- WriteShort(-1);
+ a_Pkt.WriteBEInt16(-1);
return;
}
- WriteShort(ItemType);
- WriteByte (a_Item.m_ItemCount);
- WriteShort(a_Item.m_ItemDamage);
+ a_Pkt.WriteBEInt16(ItemType);
+ a_Pkt.WriteBEInt8(a_Item.m_ItemCount);
+ a_Pkt.WriteBEInt16(a_Item.m_ItemDamage);
if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR))
{
- WriteChar(0);
+ a_Pkt.WriteBEInt8(0);
return;
}
@@ -2914,24 +2909,24 @@ void cProtocol180::cPacketizer::WriteItem(const cItem & a_Item)
}
if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
{
- cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, static_cast<ENUM_ITEM_ID>(a_Item.m_ItemType));
}
Writer.Finish();
AString Result = Writer.GetResult();
if (Result.size() == 0)
{
- WriteChar(0);
+ a_Pkt.WriteBEInt8(0);
return;
}
- WriteBuf(Result.data(), Result.size());
+ a_Pkt.WriteBuf(Result.data(), Result.size());
}
-void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEntity)
+void cProtocol180::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity)
{
cFastNBTWriter Writer;
@@ -2939,21 +2934,20 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
{
case E_BLOCK_BEACON:
{
- cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity;
-
- Writer.AddInt("x", BeaconEntity.GetPosX());
- Writer.AddInt("y", BeaconEntity.GetPosY());
- Writer.AddInt("z", BeaconEntity.GetPosZ());
- Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
+ auto & BeaconEntity = reinterpret_cast<const cBeaconEntity &>(a_BlockEntity);
+ Writer.AddInt("x", BeaconEntity.GetPosX());
+ Writer.AddInt("y", BeaconEntity.GetPosY());
+ Writer.AddInt("z", BeaconEntity.GetPosZ());
+ Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect());
Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect());
- Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
+ Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel());
Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_COMMAND_BLOCK:
{
- cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity;
-
+ auto & CommandBlockEntity = reinterpret_cast<const cCommandBlockEntity &>(a_BlockEntity);
Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this
Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult());
Writer.AddInt("x", CommandBlockEntity.GetPosX());
@@ -2965,20 +2959,16 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
// MCS doesn't have this, so just leave it @ '@'. (geddit?)
Writer.AddString("CustomName", "@");
Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
-
if (!CommandBlockEntity.GetLastOutput().empty())
{
- AString Output;
- Printf(Output, "{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str());
-
- Writer.AddString("LastOutput", Output.c_str());
+ Writer.AddString("LastOutput", Printf("{\"text\":\"%s\"}", CommandBlockEntity.GetLastOutput().c_str()));
}
break;
}
+
case E_BLOCK_HEAD:
{
- cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity;
-
+ auto & MobHeadEntity = reinterpret_cast<const cMobHeadEntity &>(a_BlockEntity);
Writer.AddInt("x", MobHeadEntity.GetPosX());
Writer.AddInt("y", MobHeadEntity.GetPosY());
Writer.AddInt("z", MobHeadEntity.GetPosZ());
@@ -2988,10 +2978,10 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_FLOWER_POT:
{
- cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity;
-
+ auto & FlowerPotEntity = reinterpret_cast<const cFlowerPotEntity &>(a_BlockEntity);
Writer.AddInt("x", FlowerPotEntity.GetPosX());
Writer.AddInt("y", FlowerPotEntity.GetPosY());
Writer.AddInt("z", FlowerPotEntity.GetPosZ());
@@ -3000,10 +2990,10 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+
case E_BLOCK_MOB_SPAWNER:
{
- cMobSpawnerEntity & MobSpawnerEntity = (cMobSpawnerEntity &)a_BlockEntity;
-
+ auto & MobSpawnerEntity = reinterpret_cast<const cMobSpawnerEntity &>(a_BlockEntity);
Writer.AddInt("x", MobSpawnerEntity.GetPosX());
Writer.AddInt("y", MobSpawnerEntity.GetPosY());
Writer.AddInt("z", MobSpawnerEntity.GetPosZ());
@@ -3012,37 +3002,22 @@ void cProtocol180::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "MobSpawner");
break;
}
- default: break;
+
+ default:
+ {
+ break;
+ }
}
Writer.Finish();
- WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
+ a_Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
}
-void cProtocol180::cPacketizer::WriteByteAngle(double a_Angle)
-{
- WriteByte((char)(255 * a_Angle / 360));
-}
-
-
-
-
-
-void cProtocol180::cPacketizer::WriteFPInt(double a_Value)
-{
- int Value = (int)(a_Value * 32);
- WriteInt(Value);
-}
-
-
-
-
-
-void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
+void cProtocol180::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
// Common metadata:
Byte Flags = 0;
@@ -3066,21 +3041,21 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
{
Flags |= 0x20;
}
- WriteByte(0); // Byte(0) + index 0
- WriteByte(Flags);
+ a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0
+ a_Pkt.WriteBEUInt8(Flags);
switch (a_Entity.GetEntityType())
{
case cEntity::etPlayer: break; // TODO?
case cEntity::etPickup:
{
- WriteByte((5 << 5) | 10); // Slot(5) + index 10
- WriteItem(((const cPickup &)a_Entity).GetItem());
+ a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10
+ WriteItem(a_Pkt, reinterpret_cast<const cPickup &>(a_Entity).GetItem());
break;
}
case cEntity::etMinecart:
{
- WriteByte(0x51);
+ a_Pkt.WriteBEUInt8(0x51);
// The following expression makes Minecarts shake more with less health or higher damage taken
// It gets half the maximum health, and takes it away from the current health minus the half health:
@@ -3089,71 +3064,82 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
Health: 3 | 3 - (3 - 3) = 3
Health: 1 | 3 - (1 - 3) = 5
*/
- WriteInt((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4);
- WriteByte(0x52);
- WriteInt(1); // Shaking direction, doesn't seem to affect anything
- WriteByte(0x73);
- WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
+ auto & Minecart = reinterpret_cast<const cMinecart &>(a_Entity);
+ a_Pkt.WriteBEInt32((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * Minecart.LastDamage()) * 4);
+ a_Pkt.WriteBEUInt8(0x52);
+ a_Pkt.WriteBEInt32(1); // Shaking direction, doesn't seem to affect anything
+ a_Pkt.WriteBEUInt8(0x73);
+ a_Pkt.WriteBEFloat(static_cast<float>(Minecart.LastDamage() + 10)); // Damage taken / shake effect multiplyer
- if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
+ if (Minecart.GetPayload() == cMinecart::mpNone)
{
- cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
+ auto & RideableMinecart = reinterpret_cast<const cRideableMinecart &>(Minecart);
const cItem & MinecartContent = RideableMinecart.GetContent();
if (!MinecartContent.IsEmpty())
{
- WriteByte(0x54);
+ a_Pkt.WriteBEUInt8(0x54);
int Content = MinecartContent.m_ItemType;
Content |= MinecartContent.m_ItemDamage << 8;
- WriteInt(Content);
- WriteByte(0x55);
- WriteInt(RideableMinecart.GetBlockHeight());
- WriteByte(0x56);
- WriteByte(1);
+ a_Pkt.WriteBEInt32(Content);
+ a_Pkt.WriteBEUInt8(0x55);
+ a_Pkt.WriteBEInt32(RideableMinecart.GetBlockHeight());
+ a_Pkt.WriteBEUInt8(0x56);
+ a_Pkt.WriteBEUInt8(1);
}
}
- else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
+ else if (Minecart.GetPayload() == cMinecart::mpFurnace)
{
- WriteByte(0x10);
- WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cMinecartWithFurnace &>(Minecart).IsFueled() ? 1 : 0);
}
break;
- }
+ } // case etMinecart
+
case cEntity::etProjectile:
{
- cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
+ auto & Projectile = reinterpret_cast<const cProjectileEntity &>(a_Entity);
switch (Projectile.GetProjectileKind())
{
case cProjectileEntity::pkArrow:
{
- WriteByte(0x10);
- WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(reinterpret_cast<const cArrowEntity &>(Projectile).IsCritical() ? 1 : 0);
break;
}
case cProjectileEntity::pkFirework:
{
- WriteByte(0xA8);
- WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
+ a_Pkt.WriteBEUInt8(0xa8);
+ WriteItem(a_Pkt, reinterpret_cast<const cFireworkEntity &>(Projectile).GetItem());
+ break;
+ }
+ default:
+ {
break;
}
- default: break;
}
break;
- }
+ } // case etProjectile
+
case cEntity::etMonster:
{
- WriteMobMetadata((const cMonster &)a_Entity);
+ WriteMobMetadata(a_Pkt, reinterpret_cast<const cMonster &>(a_Entity));
break;
}
+
case cEntity::etItemFrame:
{
- cItemFrame & Frame = (cItemFrame &)a_Entity;
- WriteByte(0xA8);
- WriteItem(Frame.GetItem());
- WriteByte(0x09);
- WriteByte(Frame.GetItemRotation());
+ auto & Frame = reinterpret_cast<const cItemFrame &>(a_Entity);
+ a_Pkt.WriteBEUInt8(0xa8);
+ WriteItem(a_Pkt, Frame.GetItem());
+ a_Pkt.WriteBEUInt8(0x09);
+ a_Pkt.WriteBEUInt8(Frame.GetItemRotation());
+ break;
+ } // case etItemFrame
+
+ default:
+ {
break;
}
- default: break;
}
}
@@ -3161,192 +3147,205 @@ void cProtocol180::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
-void cProtocol180::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
+void cProtocol180::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob)
{
switch (a_Mob.GetMobType())
{
- case mtCreeper:
- {
- WriteByte(0x10);
- WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1);
- WriteByte(0x11);
- WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0);
- break;
- }
-
case mtBat:
{
- WriteByte(0x10);
- WriteByte(((const cBat &)a_Mob).IsHanging() ? 1 : 0);
- break;
- }
-
- case mtPig:
- {
- WriteByte(0x10);
- WriteByte(((const cPig &)a_Mob).IsSaddled() ? 1 : 0);
+ auto & Bat = reinterpret_cast<const cBat &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(Bat.IsHanging() ? 1 : 0);
break;
- }
+ } // case mtBat
- case mtVillager:
+ case mtCreeper:
{
- WriteByte(0x50);
- WriteInt(((const cVillager &)a_Mob).GetVilType());
+ auto & Creeper = reinterpret_cast<const cCreeper &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(Creeper.IsBlowing() ? 1 : -1);
+ a_Pkt.WriteBEUInt8(0x11);
+ a_Pkt.WriteBEUInt8(Creeper.IsCharged() ? 1 : 0);
break;
- }
+ } // case mtCreeper
- case mtZombie:
+ case mtEnderman:
{
- WriteByte(0x0c);
- WriteByte(((const cZombie &)a_Mob).IsBaby() ? 1 : 0);
- WriteByte(0x0d);
- WriteByte(((const cZombie &)a_Mob).IsVillagerZombie() ? 1 : 0);
- WriteByte(0x0e);
- WriteByte(((const cZombie &)a_Mob).IsConverting() ? 1 : 0);
+ auto & Enderman = reinterpret_cast<const cEnderman &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x30);
+ a_Pkt.WriteBEInt16(static_cast<Byte>(Enderman.GetCarriedBlock()));
+ a_Pkt.WriteBEUInt8(0x11);
+ a_Pkt.WriteBEUInt8(static_cast<Byte>(Enderman.GetCarriedMeta()));
+ a_Pkt.WriteBEUInt8(0x12);
+ a_Pkt.WriteBEUInt8(Enderman.IsScreaming() ? 1 : 0);
break;
- }
+ } // case mtEnderman
case mtGhast:
{
- WriteByte(0x10);
- WriteByte(((const cGhast &)a_Mob).IsCharging());
+ auto & Ghast = reinterpret_cast<const cGhast &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(Ghast.IsCharging());
break;
- }
+ } // case mtGhast
- case mtWolf:
+ case mtHorse:
{
- const cWolf & Wolf = (const cWolf &)a_Mob;
- Byte WolfStatus = 0;
- if (Wolf.IsSitting())
+ auto & Horse = reinterpret_cast<const cHorse &>(a_Mob);
+ int Flags = 0;
+ if (Horse.IsTame())
{
- WolfStatus |= 0x1;
+ Flags |= 0x02;
}
- if (Wolf.IsAngry())
+ if (Horse.IsSaddled())
{
- WolfStatus |= 0x2;
+ Flags |= 0x04;
}
- if (Wolf.IsTame())
+ if (Horse.IsChested())
{
- WolfStatus |= 0x4;
+ Flags |= 0x08;
+ }
+ if (Horse.IsBaby())
+ {
+ Flags |= 0x10;
+ }
+ if (Horse.IsEating())
+ {
+ Flags |= 0x20;
+ }
+ if (Horse.IsRearing())
+ {
+ Flags |= 0x40;
+ }
+ if (Horse.IsMthOpen())
+ {
+ Flags |= 0x80;
}
- WriteByte(0x10);
- WriteByte(WolfStatus);
-
- WriteByte(0x72);
- WriteFloat((float)(a_Mob.GetHealth()));
- WriteByte(0x13);
- WriteByte(Wolf.IsBegging() ? 1 : 0);
- WriteByte(0x14);
- WriteByte(Wolf.GetCollarColor());
+ a_Pkt.WriteBEUInt8(0x50); // Int at index 16
+ a_Pkt.WriteBEInt32(Flags);
+ a_Pkt.WriteBEUInt8(0x13); // Byte at index 19
+ a_Pkt.WriteBEUInt8(Horse.GetHorseType());
+ a_Pkt.WriteBEUInt8(0x54); // Int at index 20
+ int Appearance = 0;
+ Appearance = Horse.GetHorseColor();
+ Appearance |= Horse.GetHorseStyle() << 8;
+ a_Pkt.WriteBEInt32(Appearance);
+ a_Pkt.WriteBEUInt8(0x56); // Int at index 22
+ a_Pkt.WriteBEInt32(Horse.GetHorseArmour());
break;
- }
+ } // case mtHorse
+
+ case mtMagmaCube:
+ {
+ auto & MagmaCube = reinterpret_cast<const cMagmaCube &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(MagmaCube.GetSize());
+ break;
+ } // case mtMagmaCube
+
+ case mtPig:
+ {
+ auto & Pig = reinterpret_cast<const cPig &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(Pig.IsSaddled() ? 1 : 0);
+ break;
+ } // case mtPig
case mtSheep:
{
- WriteByte(0x10);
+ auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
Byte SheepMetadata = 0;
- SheepMetadata = ((const cSheep &)a_Mob).GetFurColor();
- if (((const cSheep &)a_Mob).IsSheared())
+ SheepMetadata = Sheep.GetFurColor();
+ if (Sheep.IsSheared())
{
SheepMetadata |= 0x10;
}
- WriteByte(SheepMetadata);
+ a_Pkt.WriteBEUInt8(SheepMetadata);
break;
- }
-
- case mtEnderman:
- {
- WriteByte(0x30);
- WriteShort((Byte)(((const cEnderman &)a_Mob).GetCarriedBlock()));
- WriteByte(0x11);
- WriteByte((Byte)(((const cEnderman &)a_Mob).GetCarriedMeta()));
- WriteByte(0x12);
- WriteByte(((const cEnderman &)a_Mob).IsScreaming() ? 1 : 0);
- break;
- }
+ } // case mtSheep
case mtSkeleton:
{
- WriteByte(0x0d);
- WriteByte(((const cSkeleton &)a_Mob).IsWither() ? 1 : 0);
+ auto & Skeleton = reinterpret_cast<const cSkeleton &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x0d);
+ a_Pkt.WriteBEUInt8(Skeleton.IsWither() ? 1 : 0);
break;
- }
+ } // case mtSkeleton
- case mtWitch:
+ case mtSlime:
{
- WriteByte(0x15);
- WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0);
+ auto & Slime = reinterpret_cast<const cSlime &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(Slime.GetSize());
break;
- }
+ } // case mtSlime
- case mtWither:
+ case mtVillager:
{
- WriteByte(0x54); // Int at index 20
- WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks());
- WriteByte(0x66); // Float at index 6
- WriteFloat((float)(a_Mob.GetHealth()));
+ auto & Villager = reinterpret_cast<const cVillager &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x50);
+ a_Pkt.WriteBEInt32(Villager.GetVilType());
break;
- }
+ } // case mtVillager
- case mtSlime:
+ case mtWitch:
{
- WriteByte(0x10);
- WriteByte(((const cSlime &)a_Mob).GetSize());
+ auto & Witch = reinterpret_cast<const cWitch &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x15);
+ a_Pkt.WriteBEUInt8(Witch.IsAngry() ? 1 : 0);
break;
- }
-
- case mtMagmaCube:
+ } // case mtWitch
+
+ case mtWither:
{
- WriteByte(0x10);
- WriteByte(((const cMagmaCube &)a_Mob).GetSize());
+ auto & Wither = reinterpret_cast<const cWither &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x54); // Int at index 20
+ a_Pkt.WriteBEInt32(Wither.GetWitherInvulnerableTicks());
+ a_Pkt.WriteBEUInt8(0x66); // Float at index 6
+ a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
break;
- }
+ } // case mtWither
- case mtHorse:
+ case mtWolf:
{
- const cHorse & Horse = (const cHorse &)a_Mob;
- int Flags = 0;
- if (Horse.IsTame())
- {
- Flags |= 0x02;
- }
- if (Horse.IsSaddled())
- {
- Flags |= 0x04;
- }
- if (Horse.IsChested())
- {
- Flags |= 0x08;
- }
- if (Horse.IsBaby())
- {
- Flags |= 0x10;
- }
- if (Horse.IsEating())
+ auto & Wolf = reinterpret_cast<const cWolf &>(a_Mob);
+ Byte WolfStatus = 0;
+ if (Wolf.IsSitting())
{
- Flags |= 0x20;
+ WolfStatus |= 0x1;
}
- if (Horse.IsRearing())
+ if (Wolf.IsAngry())
{
- Flags |= 0x40;
+ WolfStatus |= 0x2;
}
- if (Horse.IsMthOpen())
+ if (Wolf.IsTame())
{
- Flags |= 0x80;
+ WolfStatus |= 0x4;
}
- WriteByte(0x50); // Int at index 16
- WriteInt(Flags);
- WriteByte(0x13); // Byte at index 19
- WriteByte(Horse.GetHorseType());
- WriteByte(0x54); // Int at index 20
- int Appearance = 0;
- Appearance = Horse.GetHorseColor();
- Appearance |= Horse.GetHorseStyle() << 8;
- WriteInt(Appearance);
- WriteByte(0x56); // Int at index 22
- WriteInt(Horse.GetHorseArmour());
+ a_Pkt.WriteBEUInt8(0x10);
+ a_Pkt.WriteBEUInt8(WolfStatus);
+
+ a_Pkt.WriteBEUInt8(0x72);
+ a_Pkt.WriteBEFloat(static_cast<float>(a_Mob.GetHealth()));
+ a_Pkt.WriteBEUInt8(0x13);
+ a_Pkt.WriteBEUInt8(Wolf.IsBegging() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x14);
+ a_Pkt.WriteBEUInt8(Wolf.GetCollarColor());
break;
- }
+ } // case mtWolf
+
+ case mtZombie:
+ {
+ auto & Zombie = reinterpret_cast<const cZombie &>(a_Mob);
+ a_Pkt.WriteBEUInt8(0x0c);
+ a_Pkt.WriteBEUInt8(Zombie.IsBaby() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x0d);
+ a_Pkt.WriteBEUInt8(Zombie.IsVillagerZombie() ? 1 : 0);
+ a_Pkt.WriteBEUInt8(0x0e);
+ a_Pkt.WriteBEUInt8(Zombie.IsConverting() ? 1 : 0);
+ break;
+ } // case mtZombie
} // switch (a_Mob.GetType())
}
@@ -3354,12 +3353,12 @@ void cProtocol180::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
-void cProtocol180::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
+void cProtocol180::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
if (!a_Entity.IsMob())
{
// No properties for anything else than mobs
- WriteInt(0);
+ a_Pkt.WriteBEInt32(0);
return;
}
@@ -3367,7 +3366,7 @@ void cProtocol180::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
// TODO: Send properties and modifiers based on the mob type
- WriteInt(0); // NumProperties
+ a_Pkt.WriteBEInt32(0); // NumProperties
}
diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h
index 92d9825ef..9aa5ed827 100644
--- a/src/Protocol/Protocol18x.h
+++ b/src/Protocol/Protocol18x.h
@@ -62,7 +62,7 @@ public:
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
- virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
+ virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override;
@@ -150,96 +150,6 @@ public:
protected:
- /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */
- class cPacketizer
- {
- public:
- cPacketizer(cProtocol180 & a_Protocol, UInt32 a_PacketType) :
- m_Protocol(a_Protocol),
- m_Out(a_Protocol.m_OutPacketBuffer),
- m_Lock(a_Protocol.m_CSPacket)
- {
- m_Out.WriteVarInt(a_PacketType);
- }
-
- ~cPacketizer();
-
- void WriteBool(bool a_Value)
- {
- m_Out.WriteBool(a_Value);
- }
-
- void WriteByte(Byte a_Value)
- {
- m_Out.WriteByte(a_Value);
- }
-
- void WriteChar(char a_Value)
- {
- m_Out.WriteChar(a_Value);
- }
-
- void WriteShort(short a_Value)
- {
- m_Out.WriteBEShort(a_Value);
- }
-
- void WriteInt(int a_Value)
- {
- m_Out.WriteBEInt(a_Value);
- }
-
- void WriteInt64(Int64 a_Value)
- {
- m_Out.WriteBEInt64(a_Value);
- }
-
- void WriteFloat(float a_Value)
- {
- m_Out.WriteBEFloat(a_Value);
- }
-
- void WriteDouble(double a_Value)
- {
- m_Out.WriteBEDouble(a_Value);
- }
-
- void WriteVarInt(UInt32 a_Value)
- {
- m_Out.WriteVarInt(a_Value);
- }
-
- void WriteString(const AString & a_Value)
- {
- m_Out.WriteVarUTF8String(a_Value);
- }
-
- void WritePosition(int a_BlockX, int a_BlockY, int a_BlockZ)
- {
- m_Out.WritePosition(a_BlockX, a_BlockY, a_BlockZ);
- }
-
- void WriteUUID(const AString & a_UUID);
-
- void WriteBuf(const char * a_Data, size_t a_Size)
- {
- m_Out.Write(a_Data, a_Size);
- }
-
- void WriteItem(const cItem & a_Item);
- void WriteByteAngle(double a_Angle); // Writes the specified angle using a single byte
- void WriteFPInt(double a_Value); // Writes the double value as a 27:5 fixed-point integer
- void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f
- void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob
- void WriteEntityProperties(const cEntity & a_Entity); // Writes the entity properties for the specified entity, including the Count field
- void WriteBlockEntity(const cBlockEntity & a_BlockEntity);
-
- protected:
- cProtocol180 & m_Protocol;
- cByteBuffer & m_Out;
- cCSLock m_Lock;
- } ;
-
AString m_ServerAddress;
UInt16 m_ServerPort;
@@ -252,12 +162,6 @@ protected:
/** Buffer for the received data */
cByteBuffer m_ReceivedData;
- /** Buffer for composing the outgoing packets, through cPacketizer */
- cByteBuffer m_OutPacketBuffer;
-
- /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */
- cByteBuffer m_OutPacketLenBuffer;
-
bool m_IsEncrypted;
cAesCfb128Decryptor m_Decryptor;
@@ -320,6 +224,9 @@ protected:
/** Sends the data to the client, encrypting them if needed. */
virtual void SendData(const char * a_Data, size_t a_Size) override;
+ /** Sends the packet to the client. Called by the cPacketizer's destructor. */
+ virtual void SendPacket(cPacketizer & a_Packet) override;
+
void SendCompass(const cWorld & a_World);
/** Reads an item out of the received data, sets a_Item to the values read.
@@ -332,6 +239,24 @@ protected:
void StartEncryption(const Byte * a_Key);
+ /** Converts the BlockFace received by the protocol into eBlockFace constants.
+ If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */
+ eBlockFace FaceIntToBlockFace(Int8 a_FaceInt);
+
+ /** Writes the item data into a packet. */
+ void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item);
+
+ /** Writes the metadata for the specified entity, not including the terminating 0x7f. */
+ void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity);
+
+ /** Writes the mob-specific metadata for the specified mob */
+ void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob);
+
+ /** Writes the entity properties for the specified entity, including the Count field. */
+ void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity);
+
+ /** Writes the block entity data for the specified block entity into the packet. */
+ void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity);
} ;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index af9e0d1bc..36f8bc791 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -108,10 +108,10 @@ void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_Bloc
-void cProtocolRecognizer::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage)
+void cProtocolRecognizer::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
ASSERT(m_Protocol != nullptr);
- m_Protocol->SendBlockBreakAnim(a_entityID, a_BlockX, a_BlockY, a_BlockZ, stage);
+ m_Protocol->SendBlockBreakAnim(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage);
}
@@ -911,13 +911,13 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
case PROTO_VERSION_1_7_2:
{
AString ServerAddress;
- short ServerPort;
+ UInt16 ServerPort;
UInt32 NextState;
if (!m_Buffer.ReadVarUTF8String(ServerAddress))
{
break;
}
- if (!m_Buffer.ReadBEShort(ServerPort))
+ if (!m_Buffer.ReadBEUInt16(ServerPort))
{
break;
}
@@ -926,19 +926,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
break;
}
m_Buffer.CommitRead();
- m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
+ m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState);
return true;
}
case PROTO_VERSION_1_7_6:
{
AString ServerAddress;
- short ServerPort;
+ UInt16 ServerPort;
UInt32 NextState;
if (!m_Buffer.ReadVarUTF8String(ServerAddress))
{
break;
}
- if (!m_Buffer.ReadBEShort(ServerPort))
+ if (!m_Buffer.ReadBEUInt16(ServerPort))
{
break;
}
@@ -947,19 +947,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
break;
}
m_Buffer.CommitRead();
- m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
+ m_Protocol = new cProtocol176(m_Client, ServerAddress, ServerPort, NextState);
return true;
}
case PROTO_VERSION_1_8_0:
{
AString ServerAddress;
- short ServerPort;
+ UInt16 ServerPort;
UInt32 NextState;
if (!m_Buffer.ReadVarUTF8String(ServerAddress))
{
break;
}
- if (!m_Buffer.ReadBEShort(ServerPort))
+ if (!m_Buffer.ReadBEUInt16(ServerPort))
{
break;
}
@@ -968,12 +968,12 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
break;
}
m_Buffer.CommitRead();
- m_Protocol = new cProtocol180(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
+ m_Protocol = new cProtocol180(m_Client, ServerAddress, ServerPort, NextState);
return true;
}
}
- LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)",
- m_Client->GetIPString().c_str(), ProtocolVersion
+ LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))",
+ m_Client->GetIPString().c_str(), ProtocolVersion, ProtocolVersion
);
m_Client->Kick("Unsupported protocol version");
return false;
@@ -982,3 +982,15 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
+void cProtocolRecognizer::SendPacket(cPacketizer & a_Pkt)
+{
+ // This function should never be called - it needs to exists so that cProtocolRecognizer can be instantiated,
+ // but the actual sending is done by the internal m_Protocol itself.
+ LOGWARNING("%s: This function shouldn't ever be called.", __FUNCTION__);
+ ASSERT(!"Function not to be called");
+}
+
+
+
+
+
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index dcf653e75..d46d31cb1 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -50,7 +50,7 @@ public:
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
- virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
+ virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
virtual void SendChat (const AString & a_Message) override;
@@ -136,9 +136,12 @@ protected:
/** Tries to recognize a protocol in the lengthed family (1.7+), based on m_Buffer; returns true if recognized.
The packet length and type have already been read, type is 0
- The number of bytes remaining in the packet is passed as a_PacketLengthRemaining
- **/
+ The number of bytes remaining in the packet is passed as a_PacketLengthRemaining. **/
bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining);
+
+ /** Sends a single packet contained within the cPacketizer class.
+ The cPacketizer's destructor calls this to send the contained packet; protocol may transform the data (compression in 1.8 etc). */
+ virtual void SendPacket(cPacketizer & a_Pkt) override;
} ;
diff --git a/src/Root.cpp b/src/Root.cpp
index 27d87c717..87bc29627 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -84,7 +84,10 @@ void cRoot::InputThread(cRoot & a_Params)
if (m_TerminateEventRaised || !std::cin.good())
{
// We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server:
- a_Params.m_bStop = true;
+ if (m_RunAsService) // HACK: Dont kill if running as a service
+ {
+ a_Params.m_bStop = true;
+ }
}
}
@@ -268,6 +271,13 @@ void cRoot::Start(void)
+void cRoot::SetStopping(bool a_Stopping)
+{
+ m_bStop = a_Stopping;
+}
+
+
+
void cRoot::LoadGlobalSettings()
{
diff --git a/src/Root.h b/src/Root.h
index fdaf444bd..d552466dc 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -46,6 +46,7 @@ public:
// tolua_end
static bool m_TerminateEventRaised;
+ static bool m_RunAsService;
cRoot(void);
@@ -53,6 +54,9 @@ public:
void Start(void);
+ // Added so the service handler can request a stop
+ void SetStopping(bool a_Stopping);
+
// tolua_begin
cServer * GetServer(void) { return m_Server; }
cWorld * GetDefaultWorld(void);
diff --git a/src/Server.cpp b/src/Server.cpp
index 3f61be378..df2c7deef 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -549,7 +549,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
}
#endif
- else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output))
+ else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output, a_Cmd))
{
a_Output.Finished();
return;
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 8456ed11d..0ee33a3bc 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -377,7 +377,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
if (BlockType == E_BLOCK_TNT)
{
m_World.SpawnPrimedTNT(AbsX, Y, AbsZ, 0);
- Neighbour->SetBlock(X, a_RelY + Y, Z, E_BLOCK_AIR, 0);
+ Neighbour->SetBlock(X, Y, Z, E_BLOCK_AIR, 0);
return;
}
diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp
index bcd083294..a9481edb0 100644
--- a/src/Simulator/FloodyFluidSimulator.cpp
+++ b/src/Simulator/FloodyFluidSimulator.cpp
@@ -108,8 +108,9 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
{
SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
}
+
// If source creation is on, check for it here:
- else if (
+ if (
(m_NumNeighborsForSource > 0) && // Source creation is on
(MyMeta == m_Falloff) && // Only exactly one block away from a source (fast bail-out)
!IsPassableForFluid(Below) && // Only exactly 1 block deep
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 1cc5340dd..40be9c582 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -31,7 +31,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
return;
}
- else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
+ else if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
{
return;
}
@@ -556,7 +556,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_Re
if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
{
BLOCKTYPE Type = 0;
- if (a_RelBlockY + 1 >= cChunkDef::Height)
+ if (a_RelBlockY >= cChunkDef::Height - 1)
{
continue;
}
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 4eb2d48b6..4adc6a0a0 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -140,6 +140,54 @@ AStringVector StringSplit(const AString & str, const AString & delim)
+AStringVector StringSplitWithQuotes(const AString & str, const AString & delim)
+{
+ AStringVector results;
+
+ size_t cutAt = 0;
+ size_t Prev = 0;
+ size_t cutAtQuote = 0;
+
+ while ((cutAt = str.find_first_of(delim, Prev)) != str.npos)
+ {
+ AString current = str.substr(Prev, cutAt - Prev);
+ if ((current.front() == '"') || (current.front() == '\''))
+ {
+ Prev += 1;
+ cutAtQuote = str.find_first_of(current.front(), Prev);
+ if (cutAtQuote != str.npos)
+ {
+ current = str.substr(Prev, cutAtQuote - Prev);
+ cutAt = cutAtQuote + 1;
+ }
+ }
+
+ results.push_back(std::move(current));
+ Prev = cutAt + 1;
+ }
+
+ if (Prev < str.length())
+ {
+ AString current = str.substr(Prev);
+
+ // If the remant is wrapped in matching quotes, remove them:
+ if (
+ (current.length() >= 2) &&
+ ((current.front() == '"') || (current.front() == '\'')) &&
+ (current.front() == current.back())
+ )
+ {
+ current = current.substr(1, current.length() - 2);
+ }
+
+ results.push_back(current);
+ }
+
+ return results;
+}
+
+
+
AStringVector StringSplitAndTrim(const AString & str, const AString & delim)
{
diff --git a/src/StringUtils.h b/src/StringUtils.h
index bc3bb7a2c..785197763 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -41,6 +41,11 @@ extern AString & AppendPrintf (AString & a_Dst, const char * format, ...) FORMAT
Return the splitted strings as a stringvector. */
extern AStringVector StringSplit(const AString & str, const AString & delim);
+/** Split the string at any of the listed delimiters. Keeps quoted content together
+Resolves issue #490
+Return the splitted strings as a stringvector. */
+extern AStringVector StringSplitWithQuotes(const AString & str, const AString & delim);
+
/** Split the string at any of the listed delimiters and trim each value.
Returns the splitted strings as a stringvector. */
extern AStringVector StringSplitAndTrim(const AString & str, const AString & delim);
diff --git a/src/UI/AnvilWindow.cpp b/src/UI/AnvilWindow.cpp
new file mode 100644
index 000000000..daa35cf47
--- /dev/null
+++ b/src/UI/AnvilWindow.cpp
@@ -0,0 +1,83 @@
+
+// AnvilWindow.cpp
+
+// Representing the UI window for the anvil block
+
+#include "Globals.h"
+#include "AnvilWindow.h"
+#include "SlotArea.h"
+
+
+
+
+cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtAnvil, "Repair"),
+ m_RepairedItemName(""),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_AnvilSlotArea = new cSlotAreaAnvil(*this);
+ m_SlotAreas.push_back(m_AnvilSlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+AString cAnvilWindow::GetRepairedItemName(void) const
+{
+ return m_RepairedItemName;
+}
+
+
+
+
+
+void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
+{
+ m_RepairedItemName = a_Name;
+ if (a_Player != nullptr)
+ {
+ m_AnvilSlotArea->UpdateResult(*a_Player);
+ }
+}
+
+
+
+
+
+void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
+{
+ a_PosX = m_BlockX;
+ a_PosY = m_BlockY;
+ a_PosZ = m_BlockZ;
+}
+
+
+
+
+
+void cAnvilWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Anvil Slot
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Anvil */
+ }
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+}
+
+
+
+
diff --git a/src/UI/AnvilWindow.h b/src/UI/AnvilWindow.h
new file mode 100644
index 000000000..e23c744fe
--- /dev/null
+++ b/src/UI/AnvilWindow.h
@@ -0,0 +1,45 @@
+
+// AnvilWindow.h
+
+// Representing the UI window for the anvil block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cAnvilWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /** Gets the repaired item name. */
+ AString GetRepairedItemName(void) const;
+
+ /** Set the repaired item name. */
+ void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
+
+ /** Gets the Position from the Anvil */
+ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cSlotAreaAnvil * m_AnvilSlotArea;
+ AString m_RepairedItemName;
+ int m_BlockX, m_BlockY, m_BlockZ;
+};
+
+
+
+
diff --git a/src/UI/BeaconWindow.cpp b/src/UI/BeaconWindow.cpp
new file mode 100644
index 000000000..c1efa78ad
--- /dev/null
+++ b/src/UI/BeaconWindow.cpp
@@ -0,0 +1,76 @@
+
+// BeaconWindow.cpp
+
+// Representing the UI window for the beacon block
+
+#include "Globals.h"
+#include "BeaconWindow.h"
+#include "SlotArea.h"
+#include "../BlockEntities/BeaconEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) :
+ cWindow(wtBeacon, "Beacon"),
+ m_Beacon(a_Beacon)
+{
+ m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cBeaconWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Beacon Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ if (cSlotAreaBeacon::IsPlaceableItem(a_ItemStack.m_ItemType) && (a_ItemStack.m_ItemCount == 1))
+ {
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Beacon */
+ }
+
+ if (a_ClickedArea == m_SlotAreas[1])
+ {
+ // Inventory Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ }
+ else
+ {
+ // Hotbar Area
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ }
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
+
+void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player)
+{
+ super::OpenedByPlayer(a_Player);
+
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel());
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect());
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect());
+}
+
+
+
+
diff --git a/src/UI/BeaconWindow.h b/src/UI/BeaconWindow.h
new file mode 100644
index 000000000..fa28b41ba
--- /dev/null
+++ b/src/UI/BeaconWindow.h
@@ -0,0 +1,40 @@
+
+// BeaconWindow.h
+
+// Representing the UI window for the beacon block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBeaconWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon);
+
+ cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; }
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+ // cWindow Overrides:
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
+
+protected:
+ cBeaconEntity * m_Beacon;
+};
+
+
+
+
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
index 2b094ef1d..ef4afc40a 100644
--- a/src/UI/CMakeLists.txt
+++ b/src/UI/CMakeLists.txt
@@ -6,11 +6,32 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS
SlotArea.cpp
- Window.cpp)
+ Window.cpp
+ AnvilWindow.cpp
+ BeaconWindow.cpp
+ ChestWindow.cpp
+ CraftingWindow.cpp
+ DropSpenserWindow.cpp
+ EnchantingWindow.cpp
+ EnderChestWindow.cpp
+ FurnaceWindow.cpp
+ HopperWindow.cpp
+ InventoryWindow.cpp)
SET (HDRS
SlotArea.h
Window.h
+ AnvilWindow.h
+ BeaconWindow.h
+ ChestWindow.h
+ CraftingWindow.h
+ DropSpenserWindow.h
+ EnchantingWindow.h
+ EnderChestWindow.h
+ FurnaceWindow.h
+ HopperWindow.h
+ InventoryWindow.h
+ MinecartWithChestWindow.h
WindowOwner.h)
if(NOT MSVC)
diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp
new file mode 100644
index 000000000..3766b132d
--- /dev/null
+++ b/src/UI/ChestWindow.cpp
@@ -0,0 +1,141 @@
+
+// ChestWindow.cpp
+
+// Representing the UI window for the chest block
+
+#include "Globals.h"
+#include "ChestWindow.h"
+#include "../BlockEntities/ChestEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cChestWindow::cChestWindow(cChestEntity * a_Chest) :
+ cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
+ m_World(a_Chest->GetWorld()),
+ m_BlockX(a_Chest->GetPosX()),
+ m_BlockY(a_Chest->GetPosY()),
+ m_BlockZ(a_Chest->GetPosZ()),
+ m_PrimaryChest(a_Chest),
+ m_SecondaryChest(nullptr)
+{
+ m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
+}
+
+
+
+
+
+cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
+ cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
+ m_World(a_PrimaryChest->GetWorld()),
+ m_BlockX(a_PrimaryChest->GetPosX()),
+ m_BlockY(a_PrimaryChest->GetPosY()),
+ m_BlockZ(a_PrimaryChest->GetPosZ()),
+ m_PrimaryChest(a_PrimaryChest),
+ m_SecondaryChest(a_SecondaryChest)
+{
+ m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
+}
+
+
+
+
+
+cChestWindow::~cChestWindow()
+{
+ // Send out the chest-close packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
+
+ m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+}
+
+
+
+
+
+bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
+{
+ int ChunkX, ChunkZ;
+
+ m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
+ cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+
+ if (m_SecondaryChest != nullptr)
+ {
+ m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
+ cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+ }
+
+ cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
+ return true;
+}
+
+
+
+
+
+void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
+{
+ int ChunkX, ChunkZ;
+
+ m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
+ cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+
+ if (m_SecondaryChest != nullptr)
+ {
+ m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
+ cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+ }
+
+ cWindow::OpenedByPlayer(a_Player);
+}
+
+
+
+
+
+void cChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Chest Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/ChestWindow.h b/src/UI/ChestWindow.h
new file mode 100644
index 000000000..a3b20cdd9
--- /dev/null
+++ b/src/UI/ChestWindow.h
@@ -0,0 +1,45 @@
+
+// ChestWindow.h
+
+// Representing the UI window for the chest block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cChestWindow(cChestEntity * a_Chest);
+
+ cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
+
+ ~cChestWindow();
+
+ virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
+
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cWorld * m_World;
+ int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
+ cChestEntity * m_PrimaryChest;
+ cChestEntity * m_SecondaryChest;
+};
+
+
+
+
diff --git a/src/UI/CraftingWindow.cpp b/src/UI/CraftingWindow.cpp
new file mode 100644
index 000000000..ca44056f9
--- /dev/null
+++ b/src/UI/CraftingWindow.cpp
@@ -0,0 +1,61 @@
+
+// CraftingWindow.cpp
+
+// Representing the UI window for the crafting block
+
+#include "Globals.h"
+#include "CraftingWindow.h"
+#include "SlotArea.h"
+
+
+
+
+cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtWorkbench, "Crafting Table")
+{
+ m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cCraftingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Crafting Area
+ if (a_Slot == 0)
+ {
+ // Result Slot
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ }
+ else
+ {
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ }
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0));
+ }
+ else if (a_ClickedArea == m_SlotAreas[1])
+ {
+ // Inventory Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ else
+ {
+ // Hotbar
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/CraftingWindow.h b/src/UI/CraftingWindow.h
new file mode 100644
index 000000000..01b2da73a
--- /dev/null
+++ b/src/UI/CraftingWindow.h
@@ -0,0 +1,31 @@
+
+// CraftingWindow.h
+
+// Representing the UI window for the crafting block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cCraftingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+};
+
+
+
+
diff --git a/src/UI/DropSpenserWindow.cpp b/src/UI/DropSpenserWindow.cpp
new file mode 100644
index 000000000..aeb7c64b7
--- /dev/null
+++ b/src/UI/DropSpenserWindow.cpp
@@ -0,0 +1,46 @@
+
+// DropSpenserWindow.cpp
+
+// Representing the UI window for the dropper/dispenser block
+
+#include "Globals.h"
+#include "DropSpenserWindow.h"
+
+
+
+
+
+cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
+ cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper")
+{
+ m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cDropSpenserWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // DropSpenser Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* DropSpenser */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/DropSpenserWindow.h b/src/UI/DropSpenserWindow.h
new file mode 100644
index 000000000..edff936e5
--- /dev/null
+++ b/src/UI/DropSpenserWindow.h
@@ -0,0 +1,32 @@
+
+// DropSpenserWindow.h
+
+// Representing the UI window for the dropper/dispenser block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../BlockEntities/DropSpenserEntity.h"
+
+
+
+
+
+class cDropSpenserWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+};
+
+
+
+
diff --git a/src/UI/EnchantingWindow.cpp b/src/UI/EnchantingWindow.cpp
new file mode 100644
index 000000000..fe21ee83d
--- /dev/null
+++ b/src/UI/EnchantingWindow.cpp
@@ -0,0 +1,100 @@
+
+// EnchantingWindow.cpp
+
+// Representing the UI window for the enchanting block
+
+#include "Globals.h"
+#include "EnchantingWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtEnchantment, "Enchant"),
+ m_SlotArea(),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_SlotArea = new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ);
+ m_SlotAreas.push_back(m_SlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return;
+ }
+
+ m_PropertyValue[a_Property] = a_Value;
+ super::SetProperty(a_Property, a_Value, a_Player);
+}
+
+
+
+
+
+
+void cEnchantingWindow::SetProperty(short a_Property, short a_Value)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return;
+ }
+
+ m_PropertyValue[a_Property] = a_Value;
+ super::SetProperty(a_Property, a_Value);
+}
+
+
+
+
+
+short cEnchantingWindow::GetPropertyValue(short a_Property)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return 0;
+ }
+
+ return m_PropertyValue[a_Property];
+}
+
+
+
+
+
+void cEnchantingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Enchanting Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Enchanting */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/EnchantingWindow.h b/src/UI/EnchantingWindow.h
new file mode 100644
index 000000000..bf805c6c8
--- /dev/null
+++ b/src/UI/EnchantingWindow.h
@@ -0,0 +1,44 @@
+
+// EnchantingWindow.h
+
+// Representing the UI window for the enchanting block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cEnchantingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override;
+
+ virtual void SetProperty(short a_Property, short a_Value) override;
+
+ /** Return the value of a property */
+ short GetPropertyValue(short a_Property);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+ cSlotArea * m_SlotArea;
+
+protected:
+ short m_PropertyValue[3];
+ int m_BlockX, m_BlockY, m_BlockZ;
+};
+
+
+
+
diff --git a/src/UI/EnderChestWindow.cpp b/src/UI/EnderChestWindow.cpp
new file mode 100644
index 000000000..a5484468f
--- /dev/null
+++ b/src/UI/EnderChestWindow.cpp
@@ -0,0 +1,71 @@
+
+// EnderChestWindow.cpp
+
+// Representing the UI window for the enderchest block
+
+#include "Globals.h"
+#include "../World.h"
+#include "EnderChestWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
+ cWindow(wtChest, "Ender Chest"),
+ m_World(a_EnderChest->GetWorld()),
+ m_BlockX(a_EnderChest->GetPosX()),
+ m_BlockY(a_EnderChest->GetPosY()),
+ m_BlockZ(a_EnderChest->GetPosZ())
+{
+ m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
+}
+
+
+
+
+
+cEnderChestWindow::~cEnderChestWindow()
+{
+ // Send out the chest-close packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
+
+ // Play the closing sound
+ m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+}
+
+
+
+
+
+void cEnderChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Chest Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/EnderChestWindow.h b/src/UI/EnderChestWindow.h
new file mode 100644
index 000000000..006a490bf
--- /dev/null
+++ b/src/UI/EnderChestWindow.h
@@ -0,0 +1,38 @@
+
+// EnderChestWindow.h
+
+// Representing the UI window for the enderchest block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../BlockEntities/EnderChestEntity.h"
+
+
+
+
+
+class cEnderChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cEnderChestWindow(cEnderChestEntity * a_EnderChest);
+
+ ~cEnderChestWindow();
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cWorld * m_World;
+ int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet
+};
+
+
+
+
diff --git a/src/UI/FurnaceWindow.cpp b/src/UI/FurnaceWindow.cpp
new file mode 100644
index 000000000..132439ff3
--- /dev/null
+++ b/src/UI/FurnaceWindow.cpp
@@ -0,0 +1,74 @@
+
+// FurnaceWindow.cpp
+
+// Representing the UI window for the furnace block
+
+#include "Globals.h"
+#include "FurnaceWindow.h"
+#include "SlotArea.h"
+#include "../FurnaceRecipe.h"
+#include "../Root.h"
+
+
+
+
+
+cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) :
+ cWindow(wtFurnace, "Furnace")
+{
+ m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cFurnaceWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Furnace Area
+ if (a_Slot == 2)
+ {
+ // Result Slot
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Furnace Input/Fuel Slot
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ }
+ else
+ {
+ cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe();
+ if ((FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr) || (FurnaceRecipes->IsFuel(a_ItemStack)))
+ {
+ // The item is a valid input item or fuel
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Furnace Area */
+ }
+ else if (a_ClickedArea == m_SlotAreas[1])
+ {
+ // Inventory Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ }
+ else
+ {
+ // Hotbar Area
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ }
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/FurnaceWindow.h b/src/UI/FurnaceWindow.h
new file mode 100644
index 000000000..845505f8e
--- /dev/null
+++ b/src/UI/FurnaceWindow.h
@@ -0,0 +1,32 @@
+
+// FurnaceWindow.h
+
+// Representing the UI window for the furnace block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cFurnaceWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+};
+
+
+
+
diff --git a/src/UI/HopperWindow.cpp b/src/UI/HopperWindow.cpp
new file mode 100644
index 000000000..79f0767e8
--- /dev/null
+++ b/src/UI/HopperWindow.cpp
@@ -0,0 +1,48 @@
+
+// HopperWindow.cpp
+
+// Representing the UI window for the hopper block
+
+#include "Globals.h"
+#include "../BlockEntities/HopperEntity.h"
+#include "HopperWindow.h"
+#include "../BlockEntities/DropperEntity.h"
+
+
+
+
+
+cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) :
+ super(wtHopper, "Hopper")
+{
+ m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cHopperWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Hopper Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Hopper */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/HopperWindow.h b/src/UI/HopperWindow.h
new file mode 100644
index 000000000..2dec08666
--- /dev/null
+++ b/src/UI/HopperWindow.h
@@ -0,0 +1,32 @@
+
+// HopperWindow.h
+
+// Representing the UI window for the hopper block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cHopperWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+};
+
+
+
+
diff --git a/src/UI/InventoryWindow.cpp b/src/UI/InventoryWindow.cpp
new file mode 100644
index 000000000..0f876e559
--- /dev/null
+++ b/src/UI/InventoryWindow.cpp
@@ -0,0 +1,73 @@
+
+// InventoryWindow.cpp
+
+// Representing the UI window for the player inventory
+
+#include "Globals.h"
+#include "InventoryWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cInventoryWindow::cInventoryWindow(cPlayer & a_Player) :
+ cWindow(wtInventory, "Inventory"),
+ m_Player(a_Player)
+{
+ m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers
+ m_SlotAreas.push_back(new cSlotAreaArmor(*this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cInventoryWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Crafting Area
+ if (a_Slot == 0)
+ {
+ // Result Slot
+ AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */
+ }
+ else
+ {
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */
+ AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */
+ }
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0));
+ }
+ else if (a_ClickedArea == m_SlotAreas[1])
+ {
+ // Armor Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */
+ AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ else if (a_ClickedArea == m_SlotAreas[2])
+ {
+ // Inventory Area
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */
+ AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ else
+ {
+ // Hotbar
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/InventoryWindow.h b/src/UI/InventoryWindow.h
new file mode 100644
index 000000000..10952d37f
--- /dev/null
+++ b/src/UI/InventoryWindow.h
@@ -0,0 +1,34 @@
+
+// InventoryWindow.h
+
+// Representing the UI window for the player inventory
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cInventoryWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cInventoryWindow(cPlayer & a_Player);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cPlayer & m_Player;
+};
+
+
+
+
diff --git a/src/UI/MinecartWithChestWindow.h b/src/UI/MinecartWithChestWindow.h
new file mode 100644
index 000000000..a2b5283a6
--- /dev/null
+++ b/src/UI/MinecartWithChestWindow.h
@@ -0,0 +1,67 @@
+
+// MinecartWithChestWindow.h
+
+// Representing the UI window for the minecart chest entity
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../Entities/Minecart.h"
+
+
+
+
+
+class cMinecartWithChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) :
+ cWindow(wtChest, "Minecart with Chest"),
+ m_ChestCart(a_ChestCart)
+ {
+ m_SlotAreas.push_back(new cSlotAreaMinecartWithChest(a_ChestCart, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ a_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestopen", a_ChestCart->GetPosX(), a_ChestCart->GetPosY(), a_ChestCart->GetPosZ(), 1, 1);
+ }
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea* a_ClickedArea, bool a_ShouldApply) override
+ {
+ cSlotAreas AreasInOrder;
+
+ if (a_ClickedArea == m_SlotAreas[0])
+ {
+ // Chest Area
+ AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ }
+
+
+ ~cMinecartWithChestWindow()
+ {
+ m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1);
+ }
+
+private:
+ cMinecartWithChest * m_ChestCart;
+};
+
+
+
+
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index e784569d9..37683a8e5 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -1,3 +1,4 @@
+
// SlotArea.cpp
// Implements the cSlotArea class and its descendants
@@ -12,6 +13,7 @@
#include "../BlockEntities/FurnaceEntity.h"
#include "../Entities/Minecart.h"
#include "../Items/ItemHandler.h"
+#include "AnvilWindow.h"
#include "Window.h"
#include "../CraftingRecipes.h"
#include "../Root.h"
@@ -205,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_
{
// Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover:
cItem Slot(*GetSlot(a_SlotNum, a_Player));
- m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
+ m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true);
if (Slot.IsEmpty())
{
// Empty the slot completely, the client doesn't like left-over ItemType with zero count
@@ -340,31 +342,31 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player)
-void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
for (int i = 0; i < m_NumSlots; i++)
{
- const cItem * Slot = GetSlot(i, a_Player);
+ int SlotNum = (a_BackFill) ? (m_NumSlots - 1 - i) : i;
+
+ const cItem * Slot = GetSlot(SlotNum, a_Player);
if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
{
// Different items
continue;
}
- int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
+ char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
if (NumFit <= 0)
{
// Full stack already
continue;
}
- if (NumFit > a_ItemStack.m_ItemCount)
- {
- NumFit = a_ItemStack.m_ItemCount;
- }
+ NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
+
if (a_ShouldApply)
{
cItem NewSlot(a_ItemStack);
NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
- SetSlot(i, a_Player, NewSlot);
+ SetSlot(SlotNum, a_Player, NewSlot);
}
a_ItemStack.m_ItemCount -= NumFit;
if (a_ItemStack.IsEmpty())
@@ -589,12 +591,13 @@ void cSlotAreaCrafting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem &
-void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
UNUSED(a_ItemStack);
UNUSED(a_Player);
UNUSED(a_ShouldApply);
UNUSED(a_KeepEmptySlots);
+ UNUSED(a_BackFill);
}
@@ -656,7 +659,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player)
{
// Try distributing the result. If it fails, bail out:
cItem ResultCopy(Result);
- m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, false);
+ m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, false);
if (!ResultCopy.IsEmpty())
{
// Couldn't distribute all of it. Bail out
@@ -665,7 +668,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player)
// Distribute the result, this time for real:
ResultCopy = Result;
- m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, true);
+ m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, true);
// Remove the ingredients from the crafting grid and update the recipe:
cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
@@ -769,7 +772,7 @@ void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Play
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaAnvil:
-cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) :
+cSlotAreaAnvil::cSlotAreaAnvil(cWindow & a_ParentWindow) :
cSlotAreaTemporary(3, a_ParentWindow),
m_MaximumCost(0),
m_StackSizeToBeUsedInRepair(0)
@@ -894,7 +897,7 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem
return;
}
- m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
+ m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true);
if (Slot.IsEmpty())
{
Slot.Empty();
@@ -910,31 +913,31 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem
-void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
for (int i = 0; i < 2; i++)
{
- const cItem * Slot = GetSlot(i, a_Player);
+ int SlotNum = (a_BackFill) ? (2 - 1 - i) : i;
+
+ const cItem * Slot = GetSlot(SlotNum, a_Player);
if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
{
// Different items
continue;
}
- int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
+ char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
if (NumFit <= 0)
{
// Full stack already
continue;
}
- if (NumFit > a_ItemStack.m_ItemCount)
- {
- NumFit = a_ItemStack.m_ItemCount;
- }
+ NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
+
if (a_ShouldApply)
{
cItem NewSlot(a_ItemStack);
NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
- SetSlot(i, a_Player, NewSlot);
+ SetSlot(SlotNum, a_Player, NewSlot);
}
a_ItemStack.m_ItemCount -= NumFit;
if (a_ItemStack.IsEmpty())
@@ -1051,7 +1054,7 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player)
cItem SecondInput(*GetSlot(1, a_Player));
cItem Output(*GetSlot(2, a_Player));
- if (Input.IsEmpty() && !Output.IsEmpty())
+ if (Input.IsEmpty())
{
Output.Empty();
SetSlot(2, a_Player, Output);
@@ -1335,7 +1338,7 @@ void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_
-void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
const cItem * Slot = GetSlot(0, a_Player);
if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1))
@@ -1390,13 +1393,12 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnchanting:
-cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
+cSlotAreaEnchanting::cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
cSlotAreaTemporary(1, a_ParentWindow),
m_BlockX(a_BlockX),
m_BlockY(a_BlockY),
m_BlockZ(a_BlockZ)
{
- a_ParentWindow.m_SlotArea = this;
}
@@ -1503,7 +1505,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio
-void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
+void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots, bool a_BackFill)
{
const cItem * Slot = GetSlot(0, a_Player);
if (!Slot->IsEmpty())
@@ -1833,38 +1835,50 @@ void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a
-void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
- for (int i = 0; i < 2; i++)
+ int SlotNum;
+ cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe();
+
+ if (FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr)
{
- const cItem * Slot = GetSlot(i, a_Player);
- if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
- {
- // Different items
- continue;
- }
- int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
- if (NumFit <= 0)
- {
- // Full stack already
- continue;
- }
- if (NumFit > a_ItemStack.m_ItemCount)
- {
- NumFit = a_ItemStack.m_ItemCount;
- }
- if (a_ShouldApply)
- {
- cItem NewSlot(a_ItemStack);
- NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
- SetSlot(i, a_Player, NewSlot);
- }
- a_ItemStack.m_ItemCount -= NumFit;
- if (a_ItemStack.IsEmpty())
- {
- return;
- }
- } // for i - Slots
+ SlotNum = 0;
+ }
+ else if (FurnaceRecipes->IsFuel(a_ItemStack))
+ {
+ SlotNum = 1;
+ }
+ else
+ {
+ return;
+ }
+
+ const cItem * Slot = GetSlot(SlotNum, a_Player);
+ if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
+ {
+ // Different items
+ return;
+ }
+
+ char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount;
+ if (NumFit <= 0)
+ {
+ // Full stack already
+ return;
+ }
+ NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
+
+ if (a_ShouldApply)
+ {
+ cItem NewSlot(a_ItemStack);
+ NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
+ SetSlot(SlotNum, a_Player, NewSlot);
+ }
+ a_ItemStack.m_ItemCount -= NumFit;
+ if (a_ItemStack.IsEmpty())
+ {
+ return;
+ }
}
@@ -2013,7 +2027,7 @@ void cSlotAreaInventoryBase::SetSlot(int a_SlotNum, cPlayer & a_Player, const cI
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaArmor:
-void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
{
if (ItemCategory::IsHelmet(a_ItemStack.m_ItemType) && GetSlot(0, a_Player)->IsEmpty())
{
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index 1eeeb9836..0e7ba2a50 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -17,12 +17,10 @@ class cWindow;
class cPlayer;
class cBeaconEntity;
class cChestEntity;
-class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cMinecartWithChest;
class cCraftingRecipe;
-class cEnchantingWindow;
class cWorld;
@@ -73,7 +71,7 @@ public:
if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes)
If a_KeepEmptySlots is true, empty slots will be skipped and won't be filled
*/
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots);
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill);
/// Called on DblClicking to collect all stackable items into hand.
/// The items are accumulated in a_Dragging and removed from the slots immediately.
@@ -158,7 +156,7 @@ public:
}
/** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
/** Called when a player clicks in the window. Parameters taken from the click packet. */
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
@@ -246,32 +244,35 @@ public:
virtual void SetSlot (int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
// Distributing items into this area is completely disabled
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
protected:
- /// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params
- typedef std::list<std::pair<int, cCraftingRecipe> > cRecipeMap;
+ /** Maps player's EntityID -> current recipe.
+ Not a std::map because cCraftingGrid needs proper constructor params. */
+ typedef std::list<std::pair<UInt32, cCraftingRecipe> > cRecipeMap;
int m_GridSize;
cRecipeMap m_Recipes;
- /// Handles a click in the result slot. Crafts using the current recipe, if possible
+ /** Handles a click in the result slot.
+ Crafts using the current recipe, if possible. */
void ClickedResult(cPlayer & a_Player);
- /// Handles a shift-click in the result slot. Crafts using the current recipe until it changes or no more space for result.
+ /** Handles a shift-click in the result slot.
+ Crafts using the current recipe until it changes or no more space for result. */
void ShiftClickedResult(cPlayer & a_Player);
/** Handles a drop-click in the result slot. */
void DropClickedResult(cPlayer & a_Player);
- /// Updates the current recipe and result slot based on the ingredients currently in the crafting grid of the specified player
+ /** Updates the current recipe and result slot based on the ingredients currently in the crafting grid of the specified player. */
void UpdateRecipe(cPlayer & a_Player);
- /// Retrieves the recipe for the specified player from the map, or creates one if not found
+ /** Retrieves the recipe for the specified player from the map, or creates one if not found. */
cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player);
- /// Called after an item has been crafted to handle statistics e.t.c.
+ /** Called after an item has been crafted to handle statistics e.t.c. */
void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player);
} ;
@@ -285,12 +286,12 @@ class cSlotAreaAnvil :
typedef cSlotAreaTemporary super;
public:
- cSlotAreaAnvil(cAnvilWindow & a_ParentWindow);
+ cSlotAreaAnvil(cWindow & a_ParentWindow);
// cSlotArea overrides:
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override;
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
// cSlotAreaTemporary overrides:
virtual void OnPlayerRemoved(cPlayer & a_Player) override;
@@ -326,10 +327,10 @@ public:
cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow);
virtual ~cSlotAreaBeacon();
- bool IsPlaceableItem(short a_ItemType);
+ static bool IsPlaceableItem(short a_ItemType);
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
@@ -350,11 +351,11 @@ class cSlotAreaEnchanting :
typedef cSlotAreaTemporary super;
public:
- cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ);
+ cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ);
// cSlotArea overrides:
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
// cSlotAreaTemporary overrides:
@@ -439,7 +440,7 @@ public:
virtual ~cSlotAreaFurnace();
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
- virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
+ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 1598dd3e7..bb2e2a807 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -32,7 +32,6 @@ cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) :
m_WindowType(a_WindowType),
m_WindowTitle(a_WindowTitle),
m_IsDestroyed(false),
- m_ShouldDistributeToHotbarFirst(true),
m_Owner(nullptr)
{
if (a_WindowType == wtInventory)
@@ -392,43 +391,23 @@ bool cWindow::ForEachClient(cItemCallback<cClientHandle> & a_Callback)
-void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply)
+void cWindow::DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill)
{
- // Ask each slot area to take as much of the stack as it can.
- // First ask only slots that already have the same kind of item
- // Then ask any remaining slots
- for (int Pass = 0; Pass < 2; ++Pass)
+ /* Ask each slot area to take as much of the stack as it can.
+ First ask only slots that already have the same kind of item
+ Then ask any remaining slots */
+ for (size_t Pass = 0; Pass < 2; Pass++)
{
- if (m_ShouldDistributeToHotbarFirst)
+ for (auto SlotArea : a_AreasInOrder)
{
- // First distribute into the hotbar:
- if (a_ExcludeArea != m_SlotAreas.back())
- {
- m_SlotAreas.back()->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0));
- if (a_ItemStack.IsEmpty())
- {
- // Distributed it all
- return;
- }
- }
- }
-
- // The distribute to all other areas:
- cSlotAreas::iterator end = m_ShouldDistributeToHotbarFirst ? (m_SlotAreas.end() - 1) : m_SlotAreas.end();
- for (cSlotAreas::iterator itr = m_SlotAreas.begin(); itr != end; ++itr)
- {
- if (*itr == a_ExcludeArea)
- {
- continue;
- }
- (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0));
+ SlotArea->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0), a_BackFill);
if (a_ItemStack.IsEmpty())
{
// Distributed it all
return;
}
- } // for itr - m_SlotAreas[]
- } // for Pass - repeat twice
+ }
+ }
}
@@ -779,401 +758,3 @@ void cWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
-
-////////////////////////////////////////////////////////////////////////////////
-// cInventoryWindow:
-
-cInventoryWindow::cInventoryWindow(cPlayer & a_Player) :
- cWindow(wtInventory, "Inventory"),
- m_Player(a_Player)
-{
- m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers
- m_SlotAreas.push_back(new cSlotAreaArmor(*this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cCraftingWindow:
-
-cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtWorkbench, "Crafting Table")
-{
- m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cAnvilWindow:
-
-cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtAnvil, "Repair"),
- m_RepairedItemName(""),
- m_BlockX(a_BlockX),
- m_BlockY(a_BlockY),
- m_BlockZ(a_BlockZ)
-{
- m_AnvilSlotArea = new cSlotAreaAnvil(*this);
- m_SlotAreas.push_back(m_AnvilSlotArea);
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
-{
- m_RepairedItemName = a_Name;
-
- if (a_Player != nullptr)
- {
- m_AnvilSlotArea->UpdateResult(*a_Player);
- }
-}
-
-
-
-
-
-void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
-{
- a_PosX = m_BlockX;
- a_PosY = m_BlockY;
- a_PosZ = m_BlockZ;
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cBeaconWindow:
-
-cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) :
- cWindow(wtBeacon, "Beacon"),
- m_Beacon(a_Beacon)
-{
- m_ShouldDistributeToHotbarFirst = true;
- m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player)
-{
- super::OpenedByPlayer(a_Player);
-
- a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel());
- a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect());
- a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect());
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cEnchantingWindow:
-
-cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtEnchantment, "Enchant"),
- m_SlotArea(),
- m_BlockX(a_BlockX),
- m_BlockY(a_BlockY),
- m_BlockZ(a_BlockZ)
-{
- m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-void cEnchantingWindow::SetProperty(short a_Property, short a_Value)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return;
- }
-
- m_PropertyValue[a_Property] = a_Value;
- super::SetProperty(a_Property, a_Value);
-}
-
-
-
-
-
-void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return;
- }
-
- m_PropertyValue[a_Property] = a_Value;
- super::SetProperty(a_Property, a_Value, a_Player);
-}
-
-
-
-
-
-short cEnchantingWindow::GetPropertyValue(short a_Property)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return 0;
- }
-
- return m_PropertyValue[a_Property];
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cChestWindow:
-
-cChestWindow::cChestWindow(cChestEntity * a_Chest) :
- cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
- m_World(a_Chest->GetWorld()),
- m_BlockX(a_Chest->GetPosX()),
- m_BlockY(a_Chest->GetPosY()),
- m_BlockZ(a_Chest->GetPosZ()),
- m_PrimaryChest(a_Chest),
- m_SecondaryChest(nullptr)
-{
- m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-
- // Play the opening sound:
- m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
-}
-
-
-
-
-
-cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
- cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
- m_World(a_PrimaryChest->GetWorld()),
- m_BlockX(a_PrimaryChest->GetPosX()),
- m_BlockY(a_PrimaryChest->GetPosY()),
- m_BlockZ(a_PrimaryChest->GetPosZ()),
- m_PrimaryChest(a_PrimaryChest),
- m_SecondaryChest(a_SecondaryChest)
-{
- m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-
- m_ShouldDistributeToHotbarFirst = false;
-
- // Play the opening sound:
- m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
-}
-
-
-
-
-
-void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
-{
- int ChunkX, ChunkZ;
-
- m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
- cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
-
- if (m_SecondaryChest != nullptr)
- {
- m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
- cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
- }
-
- cWindow::OpenedByPlayer(a_Player);
-}
-
-
-
-
-
-bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
-{
- int ChunkX, ChunkZ;
-
- m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
- cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
-
- if (m_SecondaryChest != nullptr)
- {
- m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
- cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
- }
-
- cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
- return true;
-}
-
-
-
-
-
-cChestWindow::~cChestWindow()
-{
- // Send out the chest-close packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
-
- m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithChestWindow:
-
-cMinecartWithChestWindow::cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) :
- cWindow(wtChest, "Minecart with Chest"),
- m_ChestCart(a_ChestCart)
-{
- m_ShouldDistributeToHotbarFirst = false;
- m_SlotAreas.push_back(new cSlotAreaMinecartWithChest(a_ChestCart, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-
- a_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestopen", a_ChestCart->GetPosX(), a_ChestCart->GetPosY(), a_ChestCart->GetPosZ(), 1, 1);
-}
-
-
-
-
-
-cMinecartWithChestWindow::~cMinecartWithChestWindow()
-{
- m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cDropSpenserWindow:
-
-cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
- cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper")
-{
- m_ShouldDistributeToHotbarFirst = false;
- m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cEnderChestWindow:
-
-cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
- cWindow(wtChest, "Ender Chest"),
- m_World(a_EnderChest->GetWorld()),
- m_BlockX(a_EnderChest->GetPosX()),
- m_BlockY(a_EnderChest->GetPosY()),
- m_BlockZ(a_EnderChest->GetPosZ())
-{
- m_ShouldDistributeToHotbarFirst = false;
- m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-
- // Play the opening sound:
- m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
-}
-
-
-
-
-
-cEnderChestWindow::~cEnderChestWindow()
-{
- // Send out the chest-close packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
-
- // Play the closing sound
- m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cHopperWindow:
-
-cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) :
- super(wtHopper, "Hopper")
-{
- m_ShouldDistributeToHotbarFirst = false;
- m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cFurnaceWindow:
-
-cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) :
- cWindow(wtFurnace, "Furnace")
-{
- m_ShouldDistributeToHotbarFirst = false;
- m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
diff --git a/src/UI/Window.h b/src/UI/Window.h
index e62176d50..9821aade1 100644
--- a/src/UI/Window.h
+++ b/src/UI/Window.h
@@ -19,7 +19,6 @@ class cPlayer;
class cWindowOwner;
class cClientHandle;
class cChestEntity;
-class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cHopperEntity;
@@ -154,14 +153,19 @@ public:
/** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed!
if a_ShouldApply is true, the changes are written into the slots;
+ if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) */
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) = 0;
+
+ /** Called from DistributeStack() to distribute the stack into a_AreasInOrder; Modifies a_ItemStack as it is distributed!
+ If a_ShouldApply is true, the changes are written into the slots;
if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes)
- */
- void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply);
+ If a_BackFill is true, the areas will be filled from the back (right side). (Example: Empty Hotbar -> Item get in slot 8, not slot 0) */
+ void DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill);
- /// Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area.
- /// The items are accumulated in a_Dragging and removed from the SlotAreas immediately.
- /// If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting.
- /// Returns true if full stack has been collected, false if there's space remaining to fill.
+ /** Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area.
+ The items are accumulated in a_Dragging and removed from the SlotAreas immediately.
+ If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting.
+ Returns true if full stack has been collected, false if there's space remaining to fill. */
bool CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks);
/// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea
@@ -178,7 +182,6 @@ protected:
cPlayerList m_OpenedBy;
bool m_IsDestroyed;
- bool m_ShouldDistributeToHotbarFirst; ///< If set (default), shift+click tries to distribute to hotbar first, then other areas. False for doublechests
cWindowOwner * m_Owner;
@@ -219,188 +222,3 @@ protected:
-
-class cCraftingWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
-} ;
-
-
-
-
-
-class cAnvilWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- /** Gets the repaired item name. */
- AString GetRepairedItemName(void) const { return m_RepairedItemName; }
-
- /** Set the repaired item name. */
- void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
-
- /** Gets the Position from the Anvil */
- void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
-
-protected:
- cSlotAreaAnvil * m_AnvilSlotArea;
- AString m_RepairedItemName;
- int m_BlockX, m_BlockY, m_BlockZ;
-} ;
-
-
-
-
-
-class cBeaconWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon);
-
- cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; }
-
- // cWindow Overrides:
- virtual void OpenedByPlayer(cPlayer & a_Player) override;
-
-protected:
- cBeaconEntity * m_Beacon;
-} ;
-
-
-
-
-
-class cEnchantingWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
- virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override;
- virtual void SetProperty(short a_Property, short a_Value) override;
-
- /** Return the Value of a Property */
- short GetPropertyValue(short a_Property);
-
- cSlotArea * m_SlotArea;
-
-protected:
- short m_PropertyValue[3];
- int m_BlockX, m_BlockY, m_BlockZ;
-};
-
-
-
-
-
-class cFurnaceWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace);
-} ;
-
-
-
-
-
-class cDropSpenserWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_Dispenser);
-} ;
-
-
-
-
-
-class cHopperWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper);
-} ;
-
-
-
-
-
-class cChestWindow :
- public cWindow
-{
-public:
- cChestWindow(cChestEntity * a_Chest);
- cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
- ~cChestWindow();
-
- virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
- virtual void OpenedByPlayer(cPlayer & a_Player) override;
-
-protected:
- cWorld * m_World;
- int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
- cChestEntity * m_PrimaryChest;
- cChestEntity * m_SecondaryChest;
-} ;
-
-
-
-
-
-class cMinecartWithChestWindow :
- public cWindow
-{
-public:
- cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart);
- ~cMinecartWithChestWindow();
-private:
- cMinecartWithChest * m_ChestCart;
-};
-
-
-
-
-
-class cEnderChestWindow :
- public cWindow
-{
-public:
- cEnderChestWindow(cEnderChestEntity * a_EnderChest);
- ~cEnderChestWindow();
-
-protected:
- cWorld * m_World;
- int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet
-};
-
-
-
-
-
-class cInventoryWindow :
- public cWindow
-{
-public:
- cInventoryWindow(cPlayer & a_Player);
-
-protected:
- cPlayer & m_Player;
-
-} ;
-
-
-
-
-
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index 86a8a9a4b..1e1a9bfa9 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -95,7 +95,9 @@ struct sWebAdminPage
// tolua_begin
class cWebAdmin :
+ // tolua_end
public cHTTPServer::cCallbacks
+ // tolua_begin
{
public:
// tolua_end
diff --git a/src/World.cpp b/src/World.cpp
index 474f77b81..4480013c3 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -259,9 +259,9 @@ void cWorld::cTickThread::Execute(void)
////////////////////////////////////////////////////////////////////////////////
// cWorld:
-cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) :
+cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_LinkedOverworldName) :
m_WorldName(a_WorldName),
- m_OverworldName(a_OverworldName),
+ m_LinkedOverworldName(a_LinkedOverworldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
#ifdef __arm__
@@ -604,12 +604,12 @@ void cWorld::Start(void)
if (GetDimension() == dimOverworld)
{
- m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether");
- m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end");
+ m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether");
+ m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end");
}
else
{
- m_OverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
+ m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
}
// Adjust the enum-backed variables into their respective bounds:
@@ -667,18 +667,23 @@ void cWorld::Start(void)
void cWorld::GenerateRandomSpawn(void)
{
LOGD("Generating random spawnpoint...");
-
+ bool foundSpawnPoint = false;
// Look for a spawn point at most 100 chunks away from map center:
for (int i = 0; i < 100; i++)
{
EMCSBiome biome = GetBiomeAt((int)m_SpawnX, (int)m_SpawnZ);
+
if (
(biome != biOcean) && (biome != biFrozenOcean) && // The biome is acceptable (don't want a small ocean island)
!IsBlockWaterOrIce(GetBlock((int)m_SpawnX, GetHeight((int)m_SpawnX, (int)m_SpawnZ), (int)m_SpawnZ)) // The terrain is acceptable (don't want to spawn inside a lake / river)
)
{
- // A good spawnpoint was found
- break;
+ if (CheckPlayerSpawnPoint((int)m_SpawnX, GetHeight((int)m_SpawnX, (int)m_SpawnZ), (int)m_SpawnZ))
+ {
+ // A good spawnpoint was found
+ foundSpawnPoint = true;
+ break;
+ }
}
// Try a neighboring chunk:
if ((GetTickRandomNumber(4) % 2) == 0) // Randomise whether to increment X or Z coords
@@ -692,8 +697,60 @@ void cWorld::GenerateRandomSpawn(void)
} // for i - 100*
m_SpawnY = (double)GetHeight((int)m_SpawnX, (int)m_SpawnZ) + 1.6f; // 1.6f to accomodate player height
+ if (foundSpawnPoint)
+ {
+ LOGINFO("Generated random spawnpoint position at {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ);
+ }
+ else
+ {
+ LOGINFO("Did not find an acceptable spawnpoint. Generated a random spawnpoint position at {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ);
+ } // Maybe widen the search instead?
+
+}
+
+
+
+
+
+bool cWorld::CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ)
+{
+ // Check that spawnblock and surrounding blocks are neither solid nor water / lava
+ static const struct
+ {
+ int x, z;
+ } Coords[] =
+ {
+ { 0, 0 },
+ { -1, 0 },
+ { 1, 0 },
+ { 0, -1 },
+ { 0, 1 },
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
+ {
+ BLOCKTYPE BlockType = GetBlock(a_PosX + Coords[i].x, a_PosY, a_PosZ + Coords[i].x);
+ if (cBlockInfo::IsSolid(BlockType) || IsBlockLiquid(BlockType))
+ {
+ return false;
+ }
+ } // for i - Coords[]
+
+ // Check that the block below is solid:
+ if (!cBlockInfo::IsSolid(GetBlock(a_PosX, a_PosY - 1, a_PosZ)))
+ {
+ return false;
+ }
- LOGINFO("Generated random spawnpoint position {%i, %i, %i}", (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ);
+ // Check that all the blocks above the spawnpoint are not solid:
+ for (int i = a_PosY; i < cChunkDef::Height; i++)
+ {
+ BLOCKTYPE BlockType = GetBlock(a_PosX, i, a_PosZ);
+ if (cBlockInfo::IsSolid(BlockType))
+ {
+ return false;
+ }
+ }
+ return true;
}
@@ -827,18 +884,18 @@ void cWorld::Stop(void)
IniFile.ReadFile(m_IniFileName);
if (GetDimension() == dimOverworld)
{
- IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_NetherWorldName);
- IniFile.SetValue("LinkedWorlds", "EndWorldName", m_EndWorldName);
+ IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_LinkedNetherWorldName);
+ IniFile.SetValue("LinkedWorlds", "EndWorldName", m_LinkedEndWorldName);
}
else
{
- IniFile.SetValue("LinkedWorlds", "OverworldName", m_OverworldName);
+ IniFile.SetValue("LinkedWorlds", "OverworldName", m_LinkedOverworldName);
}
- IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel);
+ IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_TNTShrapnelLevel));
IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled);
IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes);
IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled);
- IniFile.SetValueI("General", "Weather", (int)m_Weather);
+ IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather));
IniFile.SetValueI("General", "TimeInTicks", GetTimeOfDay());
IniFile.WriteFile(m_IniFileName);
@@ -1863,7 +1920,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
-int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta)
+UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta)
{
cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta);
FallingBlock->Initialize(*this);
@@ -1874,11 +1931,12 @@ int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NI
-int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
{
if (a_Reward < 1)
{
- return -1;
+ LOGWARNING("%s: Attempting to create an experience orb with non-positive reward!", __FUNCTION__);
+ return cEntity::INVALID_ID;
}
cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward);
@@ -1890,7 +1948,7 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
-int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
+UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
{
cMinecart * Minecart;
switch (a_MinecartType)
@@ -1902,7 +1960,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break;
default:
{
- return -1;
+ return cEntity::INVALID_ID;
}
} // switch (a_MinecartType)
Minecart->Initialize(*this);
@@ -1913,7 +1971,7 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
-void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
+UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
TNT->Initialize(*this);
@@ -1922,6 +1980,7 @@ void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks,
a_InitialVelocityCoeff * 2,
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1)
);
+ return TNT->GetUniqueID();
}
@@ -2012,7 +2071,7 @@ void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char
-void cWorld::BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude)
+void cWorld::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude)
{
m_ChunkMap->BroadcastBlockBreakAnimation(a_EntityID, a_BlockX, a_BlockY, a_BlockZ, a_Stage, a_Exclude);
}
@@ -2849,8 +2908,22 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_
-bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback)
+bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
{
+ // First check the entities-to-add:
+ {
+ cCSLock Lock(m_CSEntitiesToAdd);
+ for (auto & ent: m_EntitiesToAdd)
+ {
+ if (ent->GetUniqueID() == a_UniqueID)
+ {
+ a_Callback.Item(ent);
+ return true;
+ }
+ } // for ent - m_EntitiesToAdd[]
+ }
+
+ // Then check the chunkmap:
return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback);
}
@@ -3096,14 +3169,14 @@ void cWorld::SaveAllChunks(void)
void cWorld::QueueSaveAllChunks(void)
{
- QueueTask(make_unique<cWorld::cTaskSaveAllChunks>());
+ QueueTask(std::make_shared<cWorld::cTaskSaveAllChunks>());
}
-void cWorld::QueueTask(std::unique_ptr<cTask> a_Task)
+void cWorld::QueueTask(cTaskPtr a_Task)
{
cCSLock Lock(m_CSTasks);
m_Tasks.push_back(std::move(a_Task));
@@ -3113,7 +3186,7 @@ void cWorld::QueueTask(std::unique_ptr<cTask> a_Task)
-void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task)
+void cWorld::ScheduleTask(int a_DelayTicks, cTaskPtr a_Task)
{
Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count();
@@ -3123,11 +3196,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task)
{
if ((*itr)->m_TargetTick >= TargetTick)
{
- m_ScheduledTasks.insert(itr, make_unique<cScheduledTask>(TargetTick, a_Task));
+ m_ScheduledTasks.insert(itr, cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task)));
return;
}
}
- m_ScheduledTasks.push_back(make_unique<cScheduledTask>(TargetTick, a_Task));
+ m_ScheduledTasks.push_back(cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task)));
}
@@ -3144,7 +3217,7 @@ void cWorld::AddEntity(cEntity * a_Entity)
-bool cWorld::HasEntity(int a_UniqueID)
+bool cWorld::HasEntity(UInt32 a_UniqueID)
{
// Check if the entity is in the queue to be added to the world:
{
@@ -3261,15 +3334,16 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
-int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType)
+UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType)
{
cMonster * Monster = nullptr;
Monster = cMonster::NewMonsterFromType(a_MonsterType);
- if (Monster != nullptr)
+ if (Monster == nullptr)
{
- Monster->SetPosition(a_PosX, a_PosY, a_PosZ);
+ return cEntity::INVALID_ID;
}
+ Monster->SetPosition(a_PosX, a_PosY, a_PosZ);
return SpawnMobFinalize(Monster);
}
@@ -3277,13 +3351,9 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a
-int cWorld::SpawnMobFinalize(cMonster * a_Monster)
+UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster)
{
- // Invalid cMonster object. Bail out.
- if (!a_Monster)
- {
- return -1;
- }
+ ASSERT(a_Monster != nullptr);
// Give the mob full health.
a_Monster->SetHealth(a_Monster->GetMaxHealth());
@@ -3293,7 +3363,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
{
delete a_Monster;
a_Monster = nullptr;
- return -1;
+ return cEntity::INVALID_ID;
}
// Initialize the monster into the current world.
@@ -3301,7 +3371,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
{
delete a_Monster;
a_Monster = nullptr;
- return -1;
+ return cEntity::INVALID_ID;
}
cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster);
@@ -3313,18 +3383,18 @@ 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)
+UInt32 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 == nullptr)
{
- return -1;
+ return cEntity::INVALID_ID;
}
if (!Projectile->Initialize(*this))
{
delete Projectile;
Projectile = nullptr;
- return -1;
+ return cEntity::INVALID_ID;
}
return Projectile->GetUniqueID();
}
@@ -3578,7 +3648,7 @@ void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World)
////////////////////////////////////////////////////////////////////////////////
-// cWorld::cTaskSendBlockTo
+// cWorld::cTaskSendBlockToAllPlayers
cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector<Vector3i> & a_SendQueue) :
m_SendQueue(a_SendQueue)
diff --git a/src/World.h b/src/World.h
index 3cac71a36..1de241f60 100644
--- a/src/World.h
+++ b/src/World.h
@@ -106,7 +106,8 @@ public:
virtual void Run(cWorld & a_World) = 0;
} ;
- typedef std::vector<std::unique_ptr<cTask>> cTasks;
+ typedef SharedPtr<cTask> cTaskPtr;
+ typedef std::vector<cTaskPtr> cTasks;
class cTaskSaveAllChunks :
@@ -215,7 +216,7 @@ public:
// (Please keep these alpha-sorted)
void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = nullptr); // tolua_export
- void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr);
+ void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr);
void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
// tolua_begin
@@ -335,7 +336,9 @@ public:
The entity is added lazily - this function only puts it in a queue that is then processed by the Tick thread. */
void AddEntity(cEntity * a_Entity);
- bool HasEntity(int a_UniqueID);
+ /** Returns true if an entity with the specified UniqueID exists in the world.
+ Note: Only loaded chunks are considered. */
+ bool HasEntity(UInt32 a_UniqueID);
/** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
@@ -348,8 +351,9 @@ public:
If any chunk in the box is missing, ignores the entities in that chunk silently. */
bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
- /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */
- bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+ /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
+ Returns true if entity found and callback returned false. */
+ bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
/** Compares clients of two chunks, calls the callback accordingly */
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
@@ -476,20 +480,25 @@ public:
/** Spawns item pickups for each item in the list. May compress pickups if too many entities: */
virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) override;
- /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */
+ /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified. */
virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) override;
- /** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */
- int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
+ /** Spawns an falling block entity at the given position.
+ Returns the UniqueID of the spawned falling block, or cEntity::INVALID_ID on failure. */
+ UInt32 SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
- /** Spawns an minecart at the given coordinates. */
- int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
+ /** Spawns an minecart at the given coordinates.
+ Returns the UniqueID of the spawned minecart, or cEntity::INVALID_ID on failure. */
+ UInt32 SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
- /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
- virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override;
+ /** Spawns an experience orb at the given location with the given reward.
+ Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */
+ virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override;
- /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
- void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
+ /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration.
+ Initial velocity is given based on the relative coefficient provided.
+ Returns the UniqueID of the created entity, or cEntity::INVALID_ID on failure. */
+ UInt32 SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
// tolua_end
@@ -673,14 +682,14 @@ public:
bool ShouldBroadcastAchievementMessages(void) const { return m_BroadcastAchievementMessages; }
- AString GetNetherWorldName(void) const { return m_NetherWorldName; }
- void SetNetherWorldName(const AString & a_Name) { m_NetherWorldName = a_Name; }
+ AString GetLinkedNetherWorldName(void) const { return m_LinkedNetherWorldName; }
+ void SetLinkedNetherWorldName(const AString & a_Name) { m_LinkedNetherWorldName = a_Name; }
- AString GetEndWorldName(void) const { return m_EndWorldName; }
- void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; }
+ AString GetLinkedEndWorldName(void) const { return m_LinkedEndWorldName; }
+ void SetLinkedEndWorldName(const AString & a_Name) { m_LinkedEndWorldName = a_Name; }
- AString GetLinkedOverworldName(void) const { return m_OverworldName; }
- void SetLinkedOverworldName(const AString & a_Name) { m_OverworldName = a_Name; }
+ AString GetLinkedOverworldName(void) const { return m_LinkedOverworldName; }
+ void SetLinkedOverworldName(const AString & a_Name) { m_LinkedOverworldName = a_Name; }
// tolua_end
@@ -691,11 +700,10 @@ public:
void QueueSaveAllChunks(void); // tolua_export
/** Queues a task onto the tick thread. The task object will be deleted once the task is finished */
- void QueueTask(std::unique_ptr<cTask> a_Task); // Exported in ManualBindings.cpp
+ void QueueTask(cTaskPtr a_Task); // Exported in ManualBindings.cpp
- /** Queues a task onto the tick thread, with the specified delay.
- The task object will be deleted once the task is finished */
- void ScheduleTask(int a_DelayTicks, cTask * a_Task);
+ /** Queues a task onto the tick thread, with the specified delay. */
+ void ScheduleTask(int a_DelayTicks, cTaskPtr a_Task);
/** Returns the number of chunks loaded */
int GetNumChunks() const; // tolua_export
@@ -796,14 +804,14 @@ public:
bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
- /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
- virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) override; // tolua_export
- int SpawnMobFinalize(cMonster* a_Monster);
+ /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */
+ virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) override; // tolua_export
+
+ UInt32 SpawnMobFinalize(cMonster * a_Monster);
- /** 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 = nullptr); // tolua_export
+ /** Creates a projectile of the specified type. Returns the projectile's UniqueID if successful, cEntity::INVALID_ID otherwise
+ Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */
+ UInt32 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 = nullptr); // 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(int a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
@@ -867,20 +875,16 @@ private:
{
public:
Int64 m_TargetTick;
- cTask * m_Task;
+ cTaskPtr m_Task;
/** Creates a new scheduled task; takes ownership of the task object passed to it. */
- cScheduledTask(Int64 a_TargetTick, cTask * a_Task) :
+ cScheduledTask(Int64 a_TargetTick, cTaskPtr a_Task) :
m_TargetTick(a_TargetTick),
m_Task(a_Task)
{
}
- virtual ~cScheduledTask()
- {
- delete m_Task;
- m_Task = nullptr;
- }
+ virtual ~cScheduledTask() {}
};
typedef std::unique_ptr<cScheduledTask> cScheduledTaskPtr;
@@ -889,10 +893,9 @@ private:
AString m_WorldName;
- /** The name of the world that a portal in this world should link to
- Only has effect if this world is a nether or end world, as it is used by entities to see which world to teleport to when in a portal
- */
- AString m_OverworldName;
+ /** The name of the overworld that portals in this world should link to.
+ Only has effect if this world is a Nether or End world. */
+ AString m_LinkedOverworldName;
AString m_IniFileName;
@@ -985,11 +988,13 @@ private:
/** The maximum view distance that a player can have in this world. */
int m_MaxViewDistance;
- /** Name of the nether world */
- AString m_NetherWorldName;
+ /** Name of the nether world - where Nether portals should teleport.
+ Only used when this world is an Overworld. */
+ AString m_LinkedNetherWorldName;
- /** Name of the end world */
- AString m_EndWorldName;
+ /** Name of the End world - where End portals should teleport.
+ Only used when this world is an Overworld. */
+ AString m_LinkedEndWorldName;
cChunkGenerator m_Generator;
@@ -1049,7 +1054,7 @@ private:
cSetChunkDataPtrs m_SetChunkDataQueue;
- cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = "");
+ cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_LinkedOverworldName = "");
virtual ~cWorld();
void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec);
@@ -1077,6 +1082,9 @@ private:
/** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */
void GenerateRandomSpawn(void);
+ /** Check if player starting point is acceptable **/
+ bool CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ);
+
/** Chooses a reasonable transition from the current weather to a new weather **/
eWeather ChooseNewWeather(void);
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index c87397542..10231ae3b 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -36,20 +36,9 @@
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
+#include "../Entities/Painting.h"
-#include "../Mobs/Monster.h"
-#include "../Mobs/Bat.h"
-#include "../Mobs/Creeper.h"
-#include "../Mobs/Enderman.h"
-#include "../Mobs/Horse.h"
-#include "../Mobs/MagmaCube.h"
-#include "../Mobs/Sheep.h"
-#include "../Mobs/Slime.h"
-#include "../Mobs/Skeleton.h"
-#include "../Mobs/Villager.h"
-#include "../Mobs/Wither.h"
-#include "../Mobs/Wolf.h"
-#include "../Mobs/Zombie.h"
+#include "../Mobs/IncludeAllMonsters.h"
@@ -726,24 +715,10 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
{
- m_Writer.AddInt("TileX", a_Hanging->GetBlockX());
- m_Writer.AddInt("TileY", a_Hanging->GetBlockY());
- m_Writer.AddInt("TileZ", a_Hanging->GetBlockZ());
- switch (a_Hanging->GetFacing())
- {
- case BLOCK_FACE_XM: m_Writer.AddByte("Facing", 1); break;
- case BLOCK_FACE_XP: m_Writer.AddByte("Facing", 3); break;
- case BLOCK_FACE_ZM: m_Writer.AddByte("Facing", 2); break;
- case BLOCK_FACE_ZP: m_Writer.AddByte("Facing", 0); break;
-
- case BLOCK_FACE_YM:
- case BLOCK_FACE_YP:
- case BLOCK_FACE_NONE:
- {
- // These directions are invalid, but they may have been previously loaded, so keep them.
- break;
- }
- }
+ m_Writer.AddInt("TileX", FloorC(a_Hanging->GetPosX()));
+ m_Writer.AddInt("TileY", FloorC(a_Hanging->GetPosY()));
+ m_Writer.AddInt("TileZ", FloorC(a_Hanging->GetPosZ()));
+ m_Writer.AddByte("Facing", a_Hanging->GetProtocolFacing());
}
@@ -790,6 +765,19 @@ void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
+void cNBTChunkSerializer::AddPaintingEntity(cPainting * a_Painting)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_Painting, "Painting");
+ AddHangingEntity(a_Painting);
+ m_Writer.AddString("Motive", a_Painting->GetName());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -888,7 +876,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break;
case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break;
- case cEntity::etPainting: /* TODO */ break;
+ case cEntity::etPainting: AddPaintingEntity (reinterpret_cast<cPainting *>(a_Entity)); break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
{
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 4c066b9af..f30cd59d5 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -48,6 +48,7 @@ class cTNTEntity;
class cExpOrb;
class cHangingEntity;
class cItemFrame;
+class cPainting;
class cEntityEffect;
@@ -123,6 +124,7 @@ protected:
void AddTNTEntity (cTNTEntity * a_TNT);
void AddExpOrbEntity (cExpOrb * a_ExpOrb);
void AddItemFrameEntity (cItemFrame * a_ItemFrame);
+ void AddPaintingEntity (cPainting * a_Painting);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index cc8b8d3f5..7244bcb73 100755
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -50,6 +50,7 @@
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
+#include "../Entities/Painting.h"
#include "../Protocol/MojangAPI.h"
#include "Server.h"
@@ -1337,6 +1338,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "Painting", a_IDTagLength) == 0)
+ {
+ LoadPaintingFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
{
LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1747,52 +1752,22 @@ void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT
{
// "Facing" tag is the prime source of the Facing; if not available, translate from older "Direction" or "Dir"
int Facing = a_NBT.FindChildByName(a_TagIdx, "Facing");
- if (Facing > 0)
+ if (Facing < 0)
{
- Facing = (int)a_NBT.GetByte(Facing);
- if ((Facing >= 2) && (Facing <= 5))
- {
- a_Hanging.SetFacing(static_cast<eBlockFace>(Facing));
- }
- }
- else
- {
- Facing = a_NBT.FindChildByName(a_TagIdx, "Direction");
- if (Facing > 0)
- {
- switch ((int)a_NBT.GetByte(Facing))
- {
- case 0: a_Hanging.SetFacing(BLOCK_FACE_ZM); break;
- case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break;
- case 2: a_Hanging.SetFacing(BLOCK_FACE_ZP); break;
- case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break;
- }
- }
- else
- {
- Facing = a_NBT.FindChildByName(a_TagIdx, "Dir"); // Has values 0 and 2 swapped
- if (Facing > 0)
- {
- switch ((int)a_NBT.GetByte(Facing))
- {
- case 0: a_Hanging.SetFacing(BLOCK_FACE_ZP); break;
- case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break;
- case 2: a_Hanging.SetFacing(BLOCK_FACE_ZM); break;
- case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break;
- }
- }
- }
+ return;
}
+ a_Hanging.SetProtocolFacing(a_NBT.GetByte(Facing));
+
int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
{
a_Hanging.SetPosition(
- (double)a_NBT.GetInt(TileX),
- (double)a_NBT.GetInt(TileY),
- (double)a_NBT.GetInt(TileZ)
+ static_cast<double>(a_NBT.GetInt(TileX)),
+ static_cast<double>(a_NBT.GetInt(TileY)),
+ static_cast<double>(a_NBT.GetInt(TileZ))
);
}
}
@@ -1838,6 +1813,29 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT
+void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ // Load painting name:
+ int MotiveTag = a_NBT.FindChildByName(a_TagIdx, "Motive");
+ if ((MotiveTag < 0) || (a_NBT.GetType(MotiveTag) != TAG_String))
+ {
+ return;
+ }
+
+ std::unique_ptr<cPainting> Painting(new cPainting(a_NBT.GetString(MotiveTag), BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
+ if (!LoadEntityBaseFromNBT(*Painting.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx);
+ a_Entities.push_back(Painting.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::unique_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 362796614..892645785 100755
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -166,6 +166,7 @@ protected:
void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadHangingFromNBT (cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadPaintingFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
diff --git a/src/main.cpp b/src/main.cpp
index 20609a2f8..da8eb75d4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -15,6 +15,8 @@
+/** Make the Root instance global, so it can be terminated from the worker threads */
+cRoot Root;
/** If something has told the server to stop; checked periodically in cRoot */
@@ -29,8 +31,15 @@ bool g_ShouldLogCommIn;
/** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */
bool g_ShouldLogCommOut;
+/** If set to true, binary will attempt to run as a service on Windows */
+bool cRoot::m_RunAsService = false;
+#if defined(_WIN32)
+SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
+HANDLE g_ServiceThread = INVALID_HANDLE_VALUE;
+#define SERVICE_NAME "MCServerService"
+#endif
/// If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window
@@ -179,6 +188,165 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
+////////////////////////////////////////////////////////////////////////////////
+// universalMain - Main startup logic for both standard running and as a service
+
+void universalMain()
+{
+ #ifdef _WIN32
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
+ {
+ LOGERROR("Could not install the Windows CTRL handler!");
+ }
+ #endif
+
+ // Initialize logging subsystem:
+ cLogger::InitiateMultithreading();
+
+ // Initialize LibEvent:
+ cNetworkSingleton::Get();
+
+ #if !defined(ANDROID_NDK)
+ try
+ #endif
+ {
+ Root.Start();
+ }
+ #if !defined(ANDROID_NDK)
+ catch (std::exception & e)
+ {
+ LOGERROR("Standard exception: %s", e.what());
+ }
+ catch (...)
+ {
+ LOGERROR("Unknown exception!");
+ }
+ #endif
+
+ g_ServerTerminated = true;
+
+ // Shutdown all of LibEvent:
+ cNetworkSingleton::Get().Terminate();
+}
+
+
+
+
+#if defined(_WIN32)
+////////////////////////////////////////////////////////////////////////////////
+// serviceWorkerThread: Keep the service alive
+
+DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
+{
+ UNREFERENCED_PARAMETER(lpParam);
+
+ // Do the normal startup
+ universalMain();
+
+ return ERROR_SUCCESS;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceSetState: Set the internal status of the service
+
+void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
+{
+ SERVICE_STATUS serviceStatus;
+ ZeroMemory(&serviceStatus, sizeof(SERVICE_STATUS));
+ serviceStatus.dwCheckPoint = 0;
+ serviceStatus.dwControlsAccepted = acceptedControls;
+ serviceStatus.dwCurrentState = newState;
+ serviceStatus.dwServiceSpecificExitCode = 0;
+ serviceStatus.dwServiceType = SERVICE_WIN32;
+ serviceStatus.dwWaitHint = 0;
+ serviceStatus.dwWin32ExitCode = exitCode;
+
+ if (SetServiceStatus(g_StatusHandle, &serviceStatus) == FALSE)
+ {
+ LOGERROR("SetServiceStatus() failed\n");
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceCtrlHandler: Handle stop events from the Service Control Manager
+
+void WINAPI serviceCtrlHandler(DWORD CtrlCode)
+{
+ switch (CtrlCode)
+ {
+ case SERVICE_CONTROL_STOP:
+ {
+ Root.SetStopping(true);
+ serviceSetState(0, SERVICE_STOP_PENDING, 0);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// serviceMain: Startup logic for running as a service
+
+void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
+{
+ #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP)
+ Sleep(10000);
+ #endif
+
+ char applicationFilename[MAX_PATH];
+ char applicationDirectory[MAX_PATH];
+
+ GetModuleFileName(NULL, applicationFilename, MAX_PATH); // This binaries fill path.
+
+ // GetModuleFileName() returns the path and filename. Strip off the filename.
+ strncpy(applicationDirectory, applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename));
+ applicationDirectory[strlen(applicationDirectory)] = '\0'; // Make sure new path is null terminated
+
+ // Services are run by the SCM, and inherit its working directory - usually System32.
+ // Set the working directory to the same location as the binary.
+ SetCurrentDirectory(applicationDirectory);
+
+ g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler);
+
+ if (g_StatusHandle == NULL)
+ {
+ OutputDebugString("RegisterServiceCtrlHandler() failed\n");
+ serviceSetState(0, SERVICE_STOPPED, GetLastError());
+ return;
+ }
+
+ serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0);
+
+ g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL);
+ if (g_ServiceThread == NULL)
+ {
+ OutputDebugString("CreateThread() failed\n");
+ serviceSetState(0, SERVICE_STOPPED, GetLastError());
+ return;
+ }
+ WaitForSingleObject(g_ServiceThread, INFINITE); // Wait here for a stop signal.
+
+ CloseHandle(g_ServiceThread);
+
+ serviceSetState(0, SERVICE_STOPPED, 0);
+}
+#endif
+
+
+
////////////////////////////////////////////////////////////////////////////////
// main:
@@ -219,13 +387,6 @@ int main( int argc, char **argv)
#endif // _WIN32 && !_WIN64
// End of dump-file magic
- #ifdef _WIN32
- if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
- {
- LOGERROR("Could not install the Windows CTRL handler!");
- }
- #endif
-
#if defined(_DEBUG) && defined(_MSC_VER)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@@ -280,38 +441,39 @@ int main( int argc, char **argv)
{
setvbuf(stdout, nullptr, _IONBF, 0);
}
+ else if (NoCaseCompare(Arg, "/service") == 0)
+ {
+ cRoot::m_RunAsService = true;
+ }
} // for i - argv[]
-
- cLogger::InitiateMultithreading();
-
- #if !defined(ANDROID_NDK)
- try
- #endif
- {
- cRoot Root;
- Root.Start();
- }
- #if !defined(ANDROID_NDK)
- catch (std::exception & e)
+
+ #if defined(_WIN32)
+ // Attempt to run as a service
+ if (cRoot::m_RunAsService)
{
- LOGERROR("Standard exception: %s", e.what());
+ SERVICE_TABLE_ENTRY ServiceTable[] =
+ {
+ { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain },
+ { NULL, NULL }
+ };
+
+ if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
+ {
+ LOGERROR("Attempted, but failed, service startup.");
+ return GetLastError();
+ }
}
- catch (...)
+ else
+ #endif
{
- LOGERROR("Unknown exception!");
+ // Not running as a service, do normal startup
+ universalMain();
}
- #endif
-
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
DeinitLeakFinder();
#endif
- g_ServerTerminated = true;
-
- // Shutdown all of LibEvent:
- cNetworkSingleton::Get().Terminate();
-
return EXIT_SUCCESS;
}