summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg15
-rw-r--r--src/Bindings/DeprecatedBindings.cpp275
-rw-r--r--src/Bindings/DeprecatedBindings.h8
-rw-r--r--src/Bindings/LuaChunkStay.cpp3
-rw-r--r--src/Bindings/LuaState.cpp59
-rw-r--r--src/Bindings/LuaState.h113
-rw-r--r--src/Bindings/ManualBindings.cpp461
-rw-r--r--src/Bindings/ManualBindings.h2
-rw-r--r--src/Bindings/Plugin.h3
-rw-r--r--src/Bindings/PluginLua.cpp67
-rw-r--r--src/Bindings/PluginLua.h3
-rw-r--r--src/Bindings/PluginManager.cpp65
-rw-r--r--src/Bindings/PluginManager.h11
-rw-r--r--src/Bindings/WebPlugin.cpp2
-rw-r--r--src/Bindings/lua51.dll (renamed from src/Bindings/lua5.1.dll)bin167424 -> 167424 bytes
-rw-r--r--src/Bindings/tolua++.exebin484864 -> 200192 bytes
-rw-r--r--src/BlockArea.cpp454
-rw-r--r--src/BlockArea.h78
-rw-r--r--src/BlockEntities/BlockEntity.cpp2
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp2
-rw-r--r--src/BlockEntities/DispenserEntity.cpp8
-rw-r--r--src/BlockEntities/FlowerPotEntity.cpp134
-rw-r--r--src/BlockEntities/FlowerPotEntity.h74
-rw-r--r--src/BlockEntities/HopperEntity.cpp2
-rw-r--r--src/BlockEntities/JukeboxEntity.h5
-rw-r--r--src/BlockID.cpp399
-rw-r--r--src/BlockID.h41
-rw-r--r--src/BlockInfo.cpp451
-rw-r--r--src/BlockInfo.h103
-rw-r--r--src/BlockTracer.h3
-rw-r--r--src/Blocks/BlockAnvil.h61
-rw-r--r--src/Blocks/BlockBed.cpp73
-rw-r--r--src/Blocks/BlockBed.h5
-rw-r--r--src/Blocks/BlockButton.h7
-rw-r--r--src/Blocks/BlockCactus.h2
-rw-r--r--src/Blocks/BlockCake.h55
-rw-r--r--src/Blocks/BlockCauldron.h2
-rw-r--r--src/Blocks/BlockChest.h5
-rw-r--r--src/Blocks/BlockComparator.h12
-rw-r--r--src/Blocks/BlockCrops.h12
-rw-r--r--src/Blocks/BlockDirt.h19
-rw-r--r--src/Blocks/BlockDoor.cpp109
-rw-r--r--src/Blocks/BlockDoor.h17
-rw-r--r--src/Blocks/BlockDropSpenser.h19
-rw-r--r--src/Blocks/BlockEnderchest.h6
-rw-r--r--src/Blocks/BlockFenceGate.h12
-rw-r--r--src/Blocks/BlockFire.h22
-rw-r--r--src/Blocks/BlockFlowerPot.h83
-rw-r--r--src/Blocks/BlockFluid.h2
-rw-r--r--src/Blocks/BlockFurnace.h8
-rw-r--r--src/Blocks/BlockHandler.cpp62
-rw-r--r--src/Blocks/BlockHandler.h27
-rw-r--r--src/Blocks/BlockHopper.h21
-rw-r--r--src/Blocks/BlockLadder.h6
-rw-r--r--src/Blocks/BlockLeaves.h20
-rw-r--r--src/Blocks/BlockLever.h39
-rw-r--r--src/Blocks/BlockLilypad.h28
-rw-r--r--src/Blocks/BlockMobHead.h127
-rw-r--r--src/Blocks/BlockMushroom.h4
-rw-r--r--src/Blocks/BlockMycelium.h2
-rw-r--r--src/Blocks/BlockNetherWart.h15
-rw-r--r--src/Blocks/BlockPluginInterface.h6
-rw-r--r--src/Blocks/BlockPumpkin.h6
-rw-r--r--src/Blocks/BlockRail.h140
-rw-r--r--src/Blocks/BlockRedstone.h2
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h15
-rw-r--r--src/Blocks/BlockSideways.h8
-rw-r--r--src/Blocks/BlockSign.h31
-rw-r--r--src/Blocks/BlockSlab.h55
-rw-r--r--src/Blocks/BlockSnow.h2
-rw-r--r--src/Blocks/BlockStairs.h76
-rw-r--r--src/Blocks/BlockStems.h3
-rw-r--r--src/Blocks/BlockTNT.h32
-rw-r--r--src/Blocks/BlockTorch.h73
-rw-r--r--src/Blocks/BlockTrapdoor.h14
-rw-r--r--src/Blocks/BlockVine.h37
-rw-r--r--src/Blocks/BroadcastInterface.h8
-rw-r--r--src/Blocks/ChunkInterface.cpp2
-rw-r--r--src/Blocks/ChunkInterface.h31
-rw-r--r--src/Blocks/MetaRotator.h120
-rw-r--r--src/Blocks/WorldInterface.h12
-rw-r--r--src/BoundingBox.cpp2
-rw-r--r--src/BoundingBox.h2
-rw-r--r--src/ByteBuffer.cpp98
-rw-r--r--src/ByteBuffer.h32
-rw-r--r--src/CMakeLists.txt42
-rw-r--r--src/Chunk.cpp58
-rw-r--r--src/Chunk.h11
-rw-r--r--src/ChunkDef.h39
-rw-r--r--src/ChunkMap.cpp153
-rw-r--r--src/ChunkMap.h9
-rw-r--r--src/ClientHandle.cpp185
-rw-r--r--src/ClientHandle.h14
-rw-r--r--src/CommandOutput.cpp4
-rw-r--r--src/CommandOutput.h2
-rw-r--r--src/CompositeChat.cpp120
-rw-r--r--src/CompositeChat.h26
-rw-r--r--src/CraftingRecipes.cpp91
-rw-r--r--src/CraftingRecipes.h3
-rw-r--r--src/Cuboid.cpp54
-rw-r--r--src/Cuboid.h15
-rw-r--r--src/DeadlockDetect.cpp6
-rw-r--r--src/DeadlockDetect.h2
-rw-r--r--src/Defines.h131
-rw-r--r--src/Entities/Boat.cpp2
-rw-r--r--src/Entities/Effects.h2
-rw-r--r--src/Entities/EnderCrystal.cpp56
-rw-r--r--src/Entities/EnderCrystal.h33
-rw-r--r--src/Entities/Entity.cpp383
-rw-r--r--src/Entities/Entity.h43
-rw-r--r--src/Entities/ExpOrb.cpp26
-rw-r--r--src/Entities/ExpOrb.h23
-rw-r--r--src/Entities/FallingBlock.cpp19
-rw-r--r--src/Entities/Floater.h4
-rw-r--r--src/Entities/HangingEntity.cpp53
-rw-r--r--src/Entities/HangingEntity.h49
-rw-r--r--src/Entities/ItemFrame.cpp39
-rw-r--r--src/Entities/ItemFrame.h22
-rw-r--r--src/Entities/Minecart.cpp20
-rw-r--r--src/Entities/Minecart.h4
-rw-r--r--src/Entities/Painting.cpp11
-rw-r--r--src/Entities/Painting.h2
-rw-r--r--src/Entities/Pickup.cpp2
-rw-r--r--src/Entities/Pickup.h23
-rw-r--r--src/Entities/Player.cpp112
-rw-r--r--src/Entities/Player.h190
-rw-r--r--src/Entities/ProjectileEntity.cpp129
-rw-r--r--src/Entities/ProjectileEntity.h13
-rw-r--r--src/Entities/TNTEntity.cpp33
-rw-r--r--src/Entities/TNTEntity.h23
-rw-r--r--src/ForEachChunkProvider.h2
-rw-r--r--src/FurnaceRecipe.cpp2
-rw-r--r--src/Generating/BioGen.cpp16
-rw-r--r--src/Generating/Caves.cpp6
-rw-r--r--src/Generating/Caves.h16
-rw-r--r--src/Generating/ChunkDesc.cpp8
-rw-r--r--src/Generating/ChunkGenerator.cpp4
-rw-r--r--src/Generating/CompoGen.cpp4
-rw-r--r--src/Generating/ComposableGenerator.cpp171
-rw-r--r--src/Generating/ComposableGenerator.h56
-rw-r--r--src/Generating/FinishGen.cpp6
-rw-r--r--src/Generating/HeiGen.cpp2
-rw-r--r--src/Generating/MineShafts.cpp6
-rw-r--r--src/Generating/MineShafts.h6
-rw-r--r--src/Generating/NetherFortGen.cpp275
-rw-r--r--src/Generating/NetherFortGen.h86
-rw-r--r--src/Generating/Noise3DGenerator.cpp2
-rw-r--r--src/Generating/POCPieceGenerator.cpp270
-rw-r--r--src/Generating/POCPieceGenerator.h54
-rw-r--r--src/Generating/PieceGenerator.cpp625
-rw-r--r--src/Generating/PieceGenerator.h247
-rw-r--r--src/Generating/Prefab.cpp316
-rw-r--r--src/Generating/Prefab.h105
-rw-r--r--src/Generating/Prefabs/CMakeLists.txt13
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.cpp2758
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.h15
-rw-r--r--src/Generating/Ravines.cpp2
-rw-r--r--src/Generating/Ravines.h6
-rw-r--r--src/Generating/StructGen.cpp14
-rw-r--r--src/Generating/StructGen.h30
-rw-r--r--src/Generating/Trees.cpp2
-rw-r--r--src/Globals.h66
-rw-r--r--src/Group.cpp2
-rw-r--r--src/GroupManager.cpp21
-rw-r--r--src/GroupManager.h3
-rw-r--r--src/HTTPServer/EnvelopeParser.h3
-rw-r--r--src/HTTPServer/HTTPFormParser.h3
-rw-r--r--src/HTTPServer/HTTPServer.cpp4
-rw-r--r--src/HTTPServer/HTTPServer.h4
-rw-r--r--src/HTTPServer/MultipartParser.h3
-rw-r--r--src/Inventory.cpp6
-rw-r--r--src/Inventory.h2
-rw-r--r--src/Item.cpp30
-rw-r--r--src/Item.h18
-rw-r--r--src/ItemGrid.h46
-rw-r--r--src/Items/ItemBoat.h26
-rw-r--r--src/Items/ItemBucket.h8
-rw-r--r--src/Items/ItemCake.h41
-rw-r--r--src/Items/ItemHandler.cpp35
-rw-r--r--src/Items/ItemHandler.h3
-rw-r--r--src/Items/ItemItemFrame.h6
-rw-r--r--src/Items/ItemLighter.h26
-rw-r--r--src/Items/ItemLilypad.h109
-rw-r--r--src/Items/ItemMinecart.h6
-rw-r--r--src/Items/ItemPickaxe.h22
-rw-r--r--src/Items/ItemRedstoneDust.h2
-rw-r--r--src/Items/ItemShears.h5
-rw-r--r--src/Items/ItemThrowable.h6
-rw-r--r--src/LightingThread.cpp10
-rw-r--r--src/LightingThread.h12
-rw-r--r--src/LineBlockTracer.cpp2
-rw-r--r--src/LinearUpscale.h46
-rw-r--r--src/Log.cpp2
-rw-r--r--src/Log.h4
-rw-r--r--src/MCLogger.cpp23
-rw-r--r--src/MCLogger.h41
-rw-r--r--src/Map.cpp4
-rw-r--r--src/Map.h2
-rw-r--r--src/Matrix4.h224
-rw-r--r--src/Matrix4f.cpp4
-rw-r--r--src/Matrix4f.h225
-rw-r--r--src/MersenneTwister.h10
-rw-r--r--src/MobSpawner.cpp29
-rw-r--r--src/Mobs/Bat.cpp2
-rw-r--r--src/Mobs/Blaze.cpp2
-rw-r--r--src/Mobs/Blaze.h4
-rw-r--r--src/Mobs/Creeper.cpp41
-rw-r--r--src/Mobs/Creeper.h3
-rw-r--r--src/Mobs/Monster.cpp39
-rw-r--r--src/Mobs/Sheep.cpp26
-rw-r--r--src/Mobs/Skeleton.cpp2
-rw-r--r--src/Mobs/SnowGolem.cpp2
-rw-r--r--src/Mobs/Squid.cpp2
-rw-r--r--src/Mobs/Villager.cpp2
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wither.cpp78
-rw-r--r--src/Mobs/Wither.h17
-rw-r--r--src/Noise.cpp8
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp6
-rw-r--r--src/OSSupport/Errors.cpp2
-rw-r--r--src/OSSupport/File.cpp20
-rw-r--r--src/OSSupport/File.h2
-rw-r--r--src/OSSupport/GZipFile.cpp9
-rw-r--r--src/OSSupport/IsThread.h2
-rw-r--r--src/OSSupport/ListenThread.h20
-rw-r--r--src/OSSupport/Sleep.h2
-rw-r--r--src/OSSupport/Socket.cpp3
-rw-r--r--src/OSSupport/SocketThreads.cpp2
-rw-r--r--src/OSSupport/SocketThreads.h2
-rw-r--r--src/OSSupport/Thread.h2
-rw-r--r--src/Piston.cpp2
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.cpp57
-rw-r--r--src/Protocol/Protocol125.h22
-rw-r--r--src/Protocol/Protocol132.cpp4
-rw-r--r--src/Protocol/Protocol132.h2
-rw-r--r--src/Protocol/Protocol16x.cpp15
-rw-r--r--src/Protocol/Protocol17x.cpp141
-rw-r--r--src/Protocol/Protocol17x.h2
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/RCONServer.h2
-rw-r--r--src/Root.cpp18
-rw-r--r--src/Scoreboard.cpp151
-rw-r--r--src/Scoreboard.h129
-rw-r--r--src/Server.cpp4
-rw-r--r--src/Simulator/DelayedFluidSimulator.cpp2
-rw-r--r--src/Simulator/FireSimulator.cpp42
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp91
-rw-r--r--src/Simulator/FloodyFluidSimulator.h18
-rw-r--r--src/Simulator/FluidSimulator.cpp1
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp8
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.h2
-rw-r--r--src/Simulator/Simulator.cpp1
-rw-r--r--src/Simulator/Simulator.h2
-rw-r--r--src/Simulator/VanillaFluidSimulator.cpp150
-rw-r--r--src/Simulator/VanillaFluidSimulator.h42
-rw-r--r--src/StringCompression.cpp8
-rw-r--r--src/StringCompression.h4
-rw-r--r--src/StringUtils.cpp8
-rw-r--r--src/StringUtils.h14
-rw-r--r--src/Tracer.cpp6
-rw-r--r--src/Tracer.h3
-rw-r--r--src/UI/SlotArea.cpp30
-rw-r--r--src/UI/SlotArea.h6
-rw-r--r--src/UI/Window.cpp2
-rw-r--r--src/UI/WindowOwner.h4
-rw-r--r--src/Vector3.h293
-rw-r--r--src/Vector3d.cpp77
-rw-r--r--src/Vector3d.h81
-rw-r--r--src/Vector3f.cpp34
-rw-r--r--src/Vector3f.h47
-rw-r--r--src/Vector3i.cpp16
-rw-r--r--src/Vector3i.h45
-rw-r--r--src/WebAdmin.cpp1
-rw-r--r--src/World.cpp146
-rw-r--r--src/World.h132
-rw-r--r--src/WorldStorage/FastNBT.cpp16
-rw-r--r--src/WorldStorage/FastNBT.h54
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp262
-rw-r--r--src/WorldStorage/FireworksSerializer.h92
-rw-r--r--src/WorldStorage/MapSerializer.cpp6
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp124
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h12
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp193
-rw-r--r--src/WorldStorage/SchematicFileSerializer.h33
-rw-r--r--src/WorldStorage/ScoreboardSerializer.cpp14
-rw-r--r--src/WorldStorage/WSSAnvil.cpp249
-rw-r--r--src/WorldStorage/WSSAnvil.h7
-rw-r--r--src/WorldStorage/WSSCompact.cpp53
-rw-r--r--src/WorldStorage/WSSCompact.h2
-rw-r--r--src/main.cpp1
292 files changed, 12905 insertions, 3468 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 6537437cd..1cd7c74f8 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -11,6 +11,7 @@ typedef unsigned int UInt32;
typedef unsigned short UInt16;
+$cfile "../Vector3.h"
$cfile "../ChunkDef.h"
$cfile "../BiomeDef.h"
@@ -26,6 +27,7 @@ $cfile "WebPlugin.h"
$cfile "LuaWindow.h"
$cfile "../BlockID.h"
+$cfile "../BlockInfo.h"
$cfile "../StringUtils.h"
$cfile "../Defines.h"
$cfile "../ChatColor.h"
@@ -57,12 +59,10 @@ $cfile "../BlockEntities/HopperEntity.h"
$cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h"
+$cfile "../BlockEntities/MobHeadEntity.h"
+$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h"
$cfile "../Root.h"
-$cfile "../Vector3f.h"
-$cfile "../Vector3d.h"
-$cfile "../Vector3i.h"
-$cfile "../Matrix4f.h"
$cfile "../Cuboid.h"
$cfile "../BoundingBox.h"
$cfile "../Tracer.h"
@@ -75,6 +75,7 @@ $cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h"
$cfile "../Map.h"
$cfile "../MapManager.h"
+$cfile "../Scoreboard.h"
@@ -93,4 +94,10 @@ typedef unsigned char Byte;
+// Aliases
+$renaming Vector3<double> @ Vector3d
+$renaming Vector3<float> @ Vector3f
+$renaming Vector3<int> @ Vector3i
+
+
diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp
new file mode 100644
index 000000000..d51ba2da3
--- /dev/null
+++ b/src/Bindings/DeprecatedBindings.cpp
@@ -0,0 +1,275 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "DeprecatedBindings.h"
+#undef TOLUA_TEMPLATE_BIND
+#include "tolua++/include/tolua++.h"
+
+#include "Plugin.h"
+#include "PluginLua.h"
+#include "PluginManager.h"
+#include "LuaWindow.h"
+#include "LuaChunkStay.h"
+
+#include "../BlockInfo.h"
+
+
+
+
+
+/* get function: g_BlockLightValue */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue
+static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ {
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockSpreadLightFalloff */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockSpreadLightFalloff
+static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetSpreadLightFalloff((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockTransparent */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockTransparent
+static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockOneHitDig */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockOneHitDig
+static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, cBlockInfo::IsOneHitDig((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockPistonBreakable */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable
+static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, cBlockInfo::IsPistonBreakable((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockIsSnowable */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable
+static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, cBlockInfo::IsSnowable((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockRequiresSpecialTool */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool
+static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, cBlockInfo::RequiresSpecialTool((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockIsSolid */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid
+static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, (bool)cBlockInfo::IsSolid((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+/* get function: g_BlockFullyOccupiesVoxel */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockFullyOccupiesVoxel
+static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
+{
+ int BlockType;
+ #ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+ #endif
+ BlockType = (int)tolua_tonumber(tolua_S, 2, 0);
+ if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID))
+ {
+ tolua_error(tolua_S, "array indexing out of range.", NULL);
+ }
+ tolua_pushboolean(tolua_S, (bool)cBlockInfo::FullyOccupiesVoxel((BLOCKTYPE)BlockType));
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+
+
+
+
+void DeprecatedBindings::Bind(lua_State * tolua_S)
+{
+ tolua_beginmodule(tolua_S, NULL);
+
+ tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, NULL);
+ tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, NULL);
+ tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, NULL);
+ tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, NULL);
+ tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, NULL);
+ tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, NULL);
+ tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, NULL);
+ tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, NULL);
+ tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, NULL);
+
+ tolua_endmodule(tolua_S);
+}
+
+
+
+
diff --git a/src/Bindings/DeprecatedBindings.h b/src/Bindings/DeprecatedBindings.h
new file mode 100644
index 000000000..5fc3cfa80
--- /dev/null
+++ b/src/Bindings/DeprecatedBindings.h
@@ -0,0 +1,8 @@
+#pragma once
+
+struct lua_State;
+class DeprecatedBindings
+{
+public:
+ static void Bind( lua_State* tolua_S );
+};
diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp
index 0e982637f..db865cfa4 100644
--- a/src/Bindings/LuaChunkStay.cpp
+++ b/src/Bindings/LuaChunkStay.cpp
@@ -131,9 +131,6 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
- // DEBUG:
- LOGD("LuaChunkStay: Chunk [%d, %d] is now available, calling the callback...", a_ChunkX, a_ChunkZ);
-
cPluginLua::cOperation Op(m_Plugin);
Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ);
}
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 45a066efe..a33459ad2 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -11,9 +11,11 @@ extern "C"
#include "lua/src/lualib.h"
}
+#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Bindings.h"
#include "ManualBindings.h"
+#include "DeprecatedBindings.h"
// fwd: SQLite/lsqlite3.c
extern "C"
@@ -93,11 +95,20 @@ void cLuaState::Create(void)
}
m_LuaState = lua_open();
luaL_openlibs(m_LuaState);
+ m_IsOwned = true;
+}
+
+
+
+
+
+void cLuaState::RegisterAPILibs(void)
+{
tolua_AllToLua_open(m_LuaState);
ManualBindings::Bind(m_LuaState);
+ DeprecatedBindings::Bind(m_LuaState);
luaopen_lsqlite3(m_LuaState);
luaopen_lxp(m_LuaState);
- m_IsOwned = true;
}
@@ -469,6 +480,18 @@ void cLuaState::Push(cEntity * a_Entity)
+void cLuaState::Push(cProjectileEntity * a_ProjectileEntity)
+{
+ ASSERT(IsValid());
+
+ tolua_pushusertype(m_LuaState, a_ProjectileEntity, "cProjectileEntity");
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(cMonster * a_Monster)
{
ASSERT(IsValid());
@@ -675,12 +698,14 @@ void cLuaState::Push(Vector3i * a_Vector)
void cLuaState::Push(void * a_Ptr)
{
+ UNUSED(a_Ptr);
ASSERT(IsValid());
// Investigate the cause of this - what is the callstack?
- LOGWARNING("Lua engine encountered an error - attempting to push a plain pointer");
+ // One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them
+ LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead.");
+ LOGWARNING("This indicates an unimplemented part of MCS bindings");
LogStackTrace();
- ASSERT(!"A plain pointer should never be pushed on Lua stack");
lua_pushnil(m_LuaState);
m_NumCurrentFunctionArgs += 1;
@@ -714,7 +739,7 @@ void cLuaState::Push(cBlockEntity * a_BlockEntity)
-void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
{
a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
}
@@ -723,11 +748,13 @@ void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
- if (lua_isstring(m_LuaState, a_StackPos))
+ size_t len = 0;
+ const char * data = lua_tolstring(m_LuaState, a_StackPos, &len);
+ if (data != NULL)
{
- a_ReturnedVal = tolua_tocppstring(m_LuaState, a_StackPos, a_ReturnedVal.c_str());
+ a_Value.assign(data, len);
}
}
@@ -735,7 +762,7 @@ void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
@@ -747,7 +774,7 @@ void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
@@ -1067,20 +1094,20 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status)
-void cLuaState::LogStackTrace(void)
+void cLuaState::LogStackTrace(int a_StartingDepth)
{
- LogStackTrace(m_LuaState);
+ LogStackTrace(m_LuaState, a_StartingDepth);
}
-void cLuaState::LogStackTrace(lua_State * a_LuaState)
+void cLuaState::LogStackTrace(lua_State * a_LuaState, int a_StartingDepth)
{
LOGWARNING("Stack trace:");
lua_Debug entry;
- int depth = 0;
+ int depth = a_StartingDepth;
while (lua_getstack(a_LuaState, depth, &entry))
{
lua_getinfo(a_LuaState, "Sln", &entry);
@@ -1272,7 +1299,9 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
{
UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns
- LOGD((a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
+
+ // Format string consisting only of %s is used to appease the compiler
+ LOGD("%s",(a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
for (int i = lua_gettop(a_LuaState); i > 0; i--)
{
AString Value;
@@ -1297,7 +1326,7 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
- LogStackTrace(a_LuaState);
+ LogStackTrace(a_LuaState, 1);
return 1; // We left the error message on the stack as the return value
}
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index dcb660c3f..b9ca2f29b 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -29,6 +29,8 @@ extern "C"
#include "lua/src/lauxlib.h"
}
+#include "../Vector3.h"
+
@@ -36,6 +38,7 @@ extern "C"
class cWorld;
class cPlayer;
class cEntity;
+class cProjectileEntity;
class cMonster;
class cItem;
class cItems;
@@ -52,7 +55,6 @@ class cWebAdmin;
struct HTTPTemplateRequest;
class cTNTEntity;
class cCreeper;
-class Vector3i;
class cHopperEntity;
class cBlockEntity;
@@ -139,9 +141,14 @@ public:
/** Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions */
operator lua_State * (void) { return m_LuaState; }
- /** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor */
+ /** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor.
+ The regular Lua libs are registered, but the MCS API is not registered (so that Lua can be used as
+ lite-config as well), use RegisterAPILibs() to do that. */
void Create(void);
+ /** Registers all the API libraries that MCS provides into m_LuaState. */
+ void RegisterAPILibs(void);
+
/** Closes the m_LuaState, if not closed already */
void Close(void);
@@ -177,6 +184,7 @@ public:
void Push(cPlayer * a_Player);
void Push(const cPlayer * a_Player);
void Push(cEntity * a_Entity);
+ void Push(cProjectileEntity * a_ProjectileEntity);
void Push(cMonster * a_Monster);
void Push(cItem * a_Item);
void Push(cItems * a_Items);
@@ -197,6 +205,19 @@ public:
void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity);
+
+ /** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, bool & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid string. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, AString & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, int & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, double & a_Value);
+
/** Call any 0-param 0-return Lua function in a single line: */
template <typename FnT>
@@ -270,7 +291,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -292,7 +313,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
ASSERT(InitialTop == lua_gettop(m_LuaState));
return true;
@@ -315,7 +336,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -338,7 +359,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -362,7 +383,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -387,7 +408,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -414,7 +435,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -442,7 +463,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -471,7 +492,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -501,7 +522,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -532,7 +553,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -553,8 +574,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -576,8 +597,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -601,8 +622,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -627,8 +648,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -654,8 +675,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -683,8 +704,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -713,8 +734,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -743,9 +764,9 @@ public:
{
return false;
}
- GetReturn(-3, a_Ret1);
- GetReturn(-2, a_Ret2);
- GetReturn(-1, a_Ret3);
+ GetStackValue(-3, a_Ret1);
+ GetStackValue(-2, a_Ret2);
+ GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@@ -775,9 +796,9 @@ public:
{
return false;
}
- GetReturn(-3, a_Ret1);
- GetReturn(-2, a_Ret2);
- GetReturn(-1, a_Ret3);
+ GetStackValue(-3, a_Ret1);
+ GetStackValue(-2, a_Ret2);
+ GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@@ -808,11 +829,11 @@ public:
{
return false;
}
- GetReturn(-5, a_Ret1);
- GetReturn(-4, a_Ret2);
- GetReturn(-3, a_Ret3);
- GetReturn(-2, a_Ret4);
- GetReturn(-1, a_Ret5);
+ GetStackValue(-5, a_Ret1);
+ GetStackValue(-4, a_Ret2);
+ GetStackValue(-3, a_Ret3);
+ GetStackValue(-2, a_Ret4);
+ GetStackValue(-1, a_Ret5);
lua_pop(m_LuaState, 5);
return true;
}
@@ -849,10 +870,10 @@ public:
static bool ReportErrors(lua_State * a_LuaState, int status);
/** Logs all items in the current stack trace to the server console */
- void LogStackTrace(void);
+ void LogStackTrace(int a_StartingDepth = 0);
/** Logs all items in the current stack trace to the server console */
- static void LogStackTrace(lua_State * a_LuaState);
+ static void LogStackTrace(lua_State * a_LuaState, int a_StartingDepth = 0);
/** Returns the type of the item on the specified position in the stack */
AString GetTypeText(int a_StackPos);
@@ -918,18 +939,6 @@ protected:
/** Pushes a usertype of the specified class type onto the stack */
void PushUserType(void * a_Object, const char * a_Type);
- /** Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, bool & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, AString & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, int & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, double & a_ReturnedVal);
-
/**
Calls the function that has been pushed onto the stack by PushFunction(),
with arguments pushed by PushXXX().
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 461186d3b..92b410481 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ManualBindings.h"
+#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
#include "Plugin.h"
@@ -23,9 +24,11 @@
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "md5/md5.h"
#include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h"
+#include "../CompositeChat.h"
@@ -113,10 +116,44 @@ static int tolua_StringSplitAndTrim(lua_State * tolua_S)
-static int tolua_LOG(lua_State* tolua_S)
+/** Retrieves the log message from the first param on the Lua stack.
+Can take either a string or a cCompositeChat.
+*/
+static AString GetLogMessage(lua_State * tolua_S)
{
- const char* str = tolua_tocppstring(tolua_S,1,0);
- cMCLogger::GetInstance()->LogSimple( str, 0 );
+ tolua_Error err;
+ if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
+ {
+ return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->ExtractText();
+ }
+ else
+ {
+ size_t len = 0;
+ const char * str = lua_tolstring(tolua_S, 1, &len);
+ if (str != NULL)
+ {
+ return AString(str, len);
+ }
+ }
+ return "";
+}
+
+
+
+
+
+static int tolua_LOG(lua_State * tolua_S)
+{
+ // If the param is a cCompositeChat, read the log level from it:
+ cMCLogger::eLogLevel LogLevel = cMCLogger::llRegular;
+ tolua_Error err;
+ if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
+ {
+ LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->GetMessageType());
+ }
+
+ // Log the message:
+ cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel);
return 0;
}
@@ -124,10 +161,9 @@ static int tolua_LOG(lua_State* tolua_S)
-static int tolua_LOGINFO(lua_State* tolua_S)
+static int tolua_LOGINFO(lua_State * tolua_S)
{
- const char* str = tolua_tocppstring(tolua_S,1,0);
- cMCLogger::GetInstance()->LogSimple( str, 1 );
+ cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llInfo);
return 0;
}
@@ -135,10 +171,9 @@ static int tolua_LOGINFO(lua_State* tolua_S)
-static int tolua_LOGWARN(lua_State* tolua_S)
+static int tolua_LOGWARN(lua_State * tolua_S)
{
- const char* str = tolua_tocppstring(tolua_S,1,0);
- cMCLogger::GetInstance()->LogSimple( str, 2 );
+ cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llWarning);
return 0;
}
@@ -146,10 +181,9 @@ static int tolua_LOGWARN(lua_State* tolua_S)
-static int tolua_LOGERROR(lua_State* tolua_S)
+static int tolua_LOGERROR(lua_State * tolua_S)
{
- const char* str = tolua_tocppstring(tolua_S,1,0);
- cMCLogger::GetInstance()->LogSimple( str, 3 );
+ cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llError);
return 0;
}
@@ -157,6 +191,50 @@ static int tolua_LOGERROR(lua_State* tolua_S)
+static int tolua_Base64Encode(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamString(1) ||
+ !L.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ AString Src;
+ L.GetStackValue(1, Src);
+ AString res = Base64Encode(Src);
+ L.Push(res);
+ return 1;
+}
+
+
+
+
+
+static int tolua_Base64Decode(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamString(1) ||
+ !L.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ AString Src;
+ L.GetStackValue(1, Src);
+ AString res = Base64Decode(Src);
+ L.Push(res);
+ return 1;
+}
+
+
+
+
+
cPluginLua * GetLuaPlugin(lua_State * L)
{
// Get the plugin identification out of LuaState:
@@ -1495,7 +1573,8 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
}
Plugin->BindCommand(Command, FnRef);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
@@ -1519,7 +1598,10 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
// Read the arguments to this API call:
tolua_Error tolua_err;
int idx = 1;
- if (tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err))
+ if (
+ tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err) ||
+ tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
+ )
{
idx++;
}
@@ -1559,7 +1641,8 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
}
Plugin->BindConsoleCommand(Command, FnRef);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
@@ -2455,7 +2538,7 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicFile
- // Exported manually because function has been moved to SchematicFileSerilizer.cpp
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@@ -2482,10 +2565,41 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
+static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
+{
+ // function cBlockArea::LoadFromSchematicString
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamString (2) ||
+ !L.CheckParamEnd (3)
+ )
+ {
+ return 0;
+ }
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
+ return 0;
+ }
+
+ AString Data;
+ L.GetStackValue(2, Data);
+ bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
+ tolua_pushboolean(tolua_S, res);
+ return 1;
+}
+
+
+
+
+
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicFile
- // Exported manually because function has been moved to SchematicFileSerilizer.cpp
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@@ -2511,6 +2625,285 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
+static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
+{
+ // function cBlockArea::SaveToSchematicString
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamEnd (2)
+ )
+ {
+ return 0;
+ }
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
+ return 0;
+ }
+
+ AString Data;
+ if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
+ {
+ L.Push(Data);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Command, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Command);
+ L.GetStackValue(4, Style);
+ self->AddRunCommandPart(Text, Command, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddSuggestCommandPart(Message, Command, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Command, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Command);
+ L.GetStackValue(4, Style);
+ self->AddSuggestCommandPart(Text, Command, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddTextPart(Message, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Style);
+ self->AddTextPart(Text, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddTextPart(Message, Url, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Url, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Url);
+ L.GetStackValue(4, Style);
+ self->AddUrlPart(Text, Url, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_ParseText(lua_State * tolua_S)
+{
+ // function cCompositeChat:ParseText(TextMessage)
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", NULL);
+ return 0;
+ }
+
+ // Parse the text:
+ AString Text;
+ L.GetStackValue(2, Text);
+ self->ParseText(Text);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
+{
+ // function cCompositeChat:SetMessageType(MessageType)
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamNumber(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", NULL);
+ return 0;
+ }
+
+ // Set the type:
+ int MessageType;
+ L.GetStackValue(1, MessageType);
+ self->SetMessageType((eMessageType)MessageType);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
+{
+ // function cCompositeChat:UnderlineUrls()
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cCompositeChat"))
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", NULL);
+ return 0;
+ }
+
+ // Call the processing
+ self->UnderlineUrls();
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
void ManualBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
@@ -2521,18 +2914,32 @@ void ManualBindings::Bind(lua_State * tolua_S)
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_beginmodule(tolua_S, "cFile");
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cBlockArea");
- tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
- tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
- tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
- tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
- tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
- tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
+ tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
+ tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
+ tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
+ tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
+ tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
+ tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
+ tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
+ tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString);
+ tolua_endmodule(tolua_S);
+
+ tolua_beginmodule(tolua_S, "cCompositeChat");
+ tolua_function(tolua_S, "AddRunCommandPart", tolua_cCompositeChat_AddRunCommandPart);
+ tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart);
+ tolua_function(tolua_S, "AddTextPart", tolua_cCompositeChat_AddTextPart);
+ tolua_function(tolua_S, "AddUrlPart", tolua_cCompositeChat_AddUrlPart);
+ tolua_function(tolua_S, "ParseText", tolua_cCompositeChat_ParseText);
+ tolua_function(tolua_S, "SetMessageType", tolua_cCompositeChat_SetMessageType);
+ tolua_function(tolua_S, "UnderlineUrls", tolua_cCompositeChat_UnderlineUrls);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cHopperEntity");
@@ -2561,7 +2968,8 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>);
- tolua_function(tolua_S, "DoWithMobHeadBlockAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadBlockAt>);
+ tolua_function(tolua_S, "DoWithMobHeadAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>);
+ tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
@@ -2583,6 +2991,11 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cMapManager");
tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
tolua_endmodule(tolua_S);
+
+ tolua_beginmodule(tolua_S, "cScoreboard");
+ tolua_function(tolua_S, "ForEachObjective", tolua_ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>);
+ tolua_function(tolua_S, "ForEachTeam", tolua_ForEach<cScoreboard, cTeam, &cScoreboard::ForEachTeam>);
+ tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlugin");
tolua_function(tolua_S, "Call", tolua_cPlugin_Call);
diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h
index e6594947e..f38e26267 100644
--- a/src/Bindings/ManualBindings.h
+++ b/src/Bindings/ManualBindings.h
@@ -5,4 +5,4 @@ class ManualBindings
{
public:
static void Bind( lua_State* tolua_S );
-}; \ No newline at end of file
+};
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 949e4693a..df0bd4dcc 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -46,6 +46,7 @@ public:
* On all these functions, return true if you want to override default behavior and not call other plugins on that callback.
* You can also return false, so default behavior is used.
**/
+ virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) = 0;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
@@ -89,6 +90,8 @@ public:
virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
+ virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) = 0;
+ virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 45c8216be..dcc816839 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -5,7 +5,11 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#ifdef __APPLE__
+#define LUA_USE_MACOSX
+#else
#define LUA_USE_POSIX
+#endif
#include "PluginLua.h"
#include "../CommandOutput.h"
@@ -14,6 +18,7 @@ extern "C"
#include "lua/src/lualib.h"
}
+#undef TOLUA_TEMPLATE_BIND
#include "tolua++/include/tolua++.h"
@@ -75,6 +80,7 @@ bool cPluginLua::Initialize(void)
if (!m_LuaState.IsValid())
{
m_LuaState.Create();
+ m_LuaState.RegisterAPILibs();
// Inject the identification global variables into the state:
lua_pushlightuserdata(m_LuaState, this);
@@ -194,6 +200,26 @@ void cPluginLua::Tick(float a_Dt)
+bool cPluginLua::OnBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
cCSLock Lock(m_CriticalSection);
@@ -1087,6 +1113,46 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a
+bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Projectile, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Projectile, &a_HitEntity, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
@@ -1429,6 +1495,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
{
switch (a_HookType)
{
+ case cPluginManager::HOOK_BLOCK_SPREAD: return "OnBlockSpread";
case cPluginManager::HOOK_BLOCK_TO_PICKUPS: return "OnBlockToPickups";
case cPluginManager::HOOK_CHAT: return "OnChat";
case cPluginManager::HOOK_CHUNK_AVAILABLE: return "OnChunkAvailable";
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index a177f5288..59542d23a 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -69,6 +69,7 @@ public:
virtual void Tick(float a_Dt) override;
+ virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) override;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
@@ -112,6 +113,8 @@ public:
virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
+ virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) override;
+ virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index c7df6357e..6a5356c0b 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -205,6 +205,27 @@ void cPluginManager::Tick(float a_Dt)
+bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_BLOCK_SPREAD);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnBlockSpread(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginManager::CallHookBlockToPickups(
cWorld * a_World, cEntity * a_Digger,
int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
@@ -248,7 +269,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message)
{
AStringVector Split(StringSplit(a_Message, " "));
ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long
- a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", Split[0].c_str()));
+ a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", a_Message.c_str()));
LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str());
return true; // Cancel sending
}
@@ -1133,6 +1154,48 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti
+bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_BLOCK);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnProjectileHitBlock(a_Projectile))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_ENTITY);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnProjectileHitEntity(a_Projectile, a_HitEntity))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY);
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 44bc5a8d7..512bc1351 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -18,6 +18,9 @@ class cChunkDesc;
// fwd: Entities/Entity.h
class cEntity;
+// fwd: Entities/ProjectileEntity.h
+class cProjectileEntity;
+
// fwd: Mobs/Monster.h
class cMonster;
@@ -58,6 +61,7 @@ public: // tolua_export
// tolua_begin
enum PluginHook
{
+ HOOK_BLOCK_SPREAD,
HOOK_BLOCK_TO_PICKUPS,
HOOK_CHAT,
HOOK_CHUNK_AVAILABLE,
@@ -101,6 +105,8 @@ public: // tolua_export
HOOK_PLUGINS_LOADED,
HOOK_POST_CRAFTING,
HOOK_PRE_CRAFTING,
+ HOOK_PROJECTILE_HIT_BLOCK,
+ HOOK_PROJECTILE_HIT_ENTITY,
HOOK_SPAWNED_ENTITY,
HOOK_SPAWNED_MONSTER,
HOOK_SPAWNING_ENTITY,
@@ -127,6 +133,8 @@ public: // tolua_export
class cCommandEnumCallback
{
public:
+ virtual ~cCommandEnumCallback() {}
+
/** Called for each command; return true to abort enumeration
For console commands, a_Permission is not used (set to empty string)
*/
@@ -154,6 +162,7 @@ public: // tolua_export
unsigned int GetNumPlugins() const; // tolua_export
// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
+ bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source);
bool CallHookBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups);
bool CallHookChat (cPlayer * a_Player, AString & a_Message);
bool CallHookChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
@@ -197,6 +206,8 @@ public: // tolua_export
bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
+ bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile);
+ bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity);
bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster);
bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity);
diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp
index 3b71d553c..bf45405ba 100644
--- a/src/Bindings/WebPlugin.cpp
+++ b/src/Bindings/WebPlugin.cpp
@@ -110,4 +110,4 @@ AString cWebPlugin::SafeString( const AString & a_String )
RetVal.push_back( c );
}
return RetVal;
-} \ No newline at end of file
+}
diff --git a/src/Bindings/lua5.1.dll b/src/Bindings/lua51.dll
index 515cf8b30..515cf8b30 100644
--- a/src/Bindings/lua5.1.dll
+++ b/src/Bindings/lua51.dll
Binary files differ
diff --git a/src/Bindings/tolua++.exe b/src/Bindings/tolua++.exe
index e5cec6d78..1e3cc7789 100644
--- a/src/Bindings/tolua++.exe
+++ b/src/Bindings/tolua++.exe
Binary files differ
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index d07ef747a..40cca8882 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -54,7 +54,7 @@ template<typename Combinator> void InternalMergeBlocks(
/// Combinator used for cBlockArea::msOverwrite merging
-static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
@@ -65,7 +65,7 @@ static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType,
/// Combinator used for cBlockArea::msFillAir merging
-static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_DstType == E_BLOCK_AIR)
{
@@ -80,7 +80,7 @@ static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N
/// Combinator used for cBlockArea::msImprint merging
-static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_SrcType != E_BLOCK_AIR)
{
@@ -95,7 +95,7 @@ static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N
/// Combinator used for cBlockArea::msLake merging
-static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// Sponge is the NOP block
if (a_SrcType == E_BLOCK_SPONGE)
@@ -158,16 +158,59 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
+/** Combinator used for cBlockArea::msSpongePrint merging */
+static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+{
+ // Sponge overwrites nothing, everything else overwrites anything
+ if (a_SrcType != E_BLOCK_SPONGE)
+ {
+ a_DstType = a_SrcType;
+ a_DstMeta = a_SrcMeta;
+ }
+}
+
+
+
+
+
+/** Combinator used for cBlockArea::msDifference merging */
+static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+{
+ if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
+ {
+ a_DstType = E_BLOCK_AIR;
+ a_DstMeta = 0;
+ }
+ else
+ {
+ a_DstType = a_SrcType;
+ a_DstMeta = a_SrcMeta;
+ }
+}
+
+
+
+
+
+/** Combinator used for cBlockArea::msMask merging */
+static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
+{
+ // If the blocks are the same, keep the dest; otherwise replace with air
+ if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
+ {
+ a_DstType = E_BLOCK_AIR;
+ a_DstMeta = 0;
+ }
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockArea:
cBlockArea::cBlockArea(void) :
- m_OriginX(0),
- m_OriginY(0),
- m_OriginZ(0),
- m_SizeX(0),
- m_SizeY(0),
- m_SizeZ(0),
m_BlockTypes(NULL),
m_BlockMetas(NULL),
m_BlockLight(NULL),
@@ -194,12 +237,8 @@ void cBlockArea::Clear(void)
delete[] m_BlockMetas; m_BlockMetas = NULL;
delete[] m_BlockLight; m_BlockLight = NULL;
delete[] m_BlockSkyLight; m_BlockSkyLight = NULL;
- m_OriginX = 0;
- m_OriginY = 0;
- m_OriginZ = 0;
- m_SizeX = 0;
- m_SizeY = 0;
- m_SizeZ = 0;
+ m_Origin.Set(0, 0, 0);
+ m_Size.Set(0, 0, 0);
}
@@ -242,12 +281,35 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
m_BlockSkyLight[i] = 0x0f;
}
}
- m_SizeX = a_SizeX;
- m_SizeY = a_SizeY;
- m_SizeZ = a_SizeZ;
- m_OriginX = 0;
- m_OriginY = 0;
- m_OriginZ = 0;
+ m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
+ m_Origin.Set(0, 0, 0);
+}
+
+
+
+
+
+void cBlockArea::Create(const Vector3i & a_Size, int a_DataTypes)
+{
+ Create(a_Size.x, a_Size.y, a_Size.z, a_DataTypes);
+}
+
+
+
+
+
+void cBlockArea::SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
+{
+ m_WEOffset.Set(a_OffsetX, a_OffsetY, a_OffsetZ);
+}
+
+
+
+
+
+void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
+{
+ m_WEOffset.Set(a_Offset.x, a_Offset.y, a_Offset.z);
}
@@ -256,9 +318,7 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
{
- m_OriginX = a_OriginX;
- m_OriginY = a_OriginY;
- m_OriginZ = a_OriginZ;
+ m_Origin.Set(a_OriginX, a_OriginY, a_OriginZ);
}
@@ -267,7 +327,7 @@ void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
void cBlockArea::SetOrigin(const Vector3i & a_Origin)
{
- SetOrigin(a_Origin.x, a_Origin.y, a_Origin.z);
+ m_Origin.Set(a_Origin.x, a_Origin.y, a_Origin.z);
}
@@ -323,9 +383,7 @@ bool cBlockArea::Read(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinB
{
return false;
}
- m_OriginX = a_MinBlockX;
- m_OriginY = a_MinBlockY;
- m_OriginZ = a_MinBlockZ;
+ m_Origin.Set(a_MinBlockX, a_MinBlockY, a_MinBlockZ);
cChunkReader Reader(*this);
// Convert block coords to chunks coords:
@@ -389,10 +447,10 @@ bool cBlockArea::Write(cForEachChunkProvider * a_ForEachChunkProvider, int a_Min
LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__);
a_MinBlockY = 0;
}
- else if (a_MinBlockY > cChunkDef::Height - m_SizeY)
+ else if (a_MinBlockY > cChunkDef::Height - m_Size.y)
{
LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__);
- a_MinBlockY = cChunkDef::Height - m_SizeY;
+ a_MinBlockY = cChunkDef::Height - m_Size.y;
}
return a_ForEachChunkProvider->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
@@ -424,10 +482,8 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
}
a_Into.Clear();
- a_Into.SetSize(m_SizeX, m_SizeY, m_SizeZ, GetDataTypes());
- a_Into.m_OriginX = m_OriginX;
- a_Into.m_OriginY = m_OriginY;
- a_Into.m_OriginZ = m_OriginZ;
+ a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
+ a_Into.m_Origin = m_Origin;
int BlockCount = GetBlockCount();
if (HasBlockTypes())
{
@@ -468,13 +524,13 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str());
return;
}
- UInt32 SizeX = ntohl(m_SizeX);
- UInt32 SizeY = ntohl(m_SizeY);
- UInt32 SizeZ = ntohl(m_SizeZ);
+ UInt32 SizeX = ntohl(m_Size.x);
+ UInt32 SizeY = ntohl(m_Size.y);
+ UInt32 SizeZ = ntohl(m_Size.z);
f.Write(&SizeX, 4);
f.Write(&SizeY, 4);
f.Write(&SizeZ, 4);
- unsigned char DataTypes = GetDataTypes();
+ unsigned char DataTypes = (unsigned char)GetDataTypes();
f.Write(&DataTypes, 1);
int NumBlocks = GetBlockCount();
if (HasBlockTypes())
@@ -513,13 +569,13 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
{
if (
- (a_AddMinX + a_SubMaxX >= m_SizeX) ||
- (a_AddMinY + a_SubMaxY >= m_SizeY) ||
- (a_AddMinZ + a_SubMaxZ >= m_SizeZ)
+ (a_AddMinX + a_SubMaxX >= m_Size.x) ||
+ (a_AddMinY + a_SubMaxY >= m_Size.y) ||
+ (a_AddMinZ + a_SubMaxZ >= m_Size.z)
)
{
LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d",
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ
);
return;
@@ -541,12 +597,10 @@ void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY
{
CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
}
- m_OriginX += a_AddMinX;
- m_OriginY += a_AddMinY;
- m_OriginZ += a_AddMinZ;
- m_SizeX -= a_AddMinX + a_SubMaxX;
- m_SizeY -= a_AddMinY + a_SubMaxY;
- m_SizeZ -= a_AddMinZ + a_SubMaxZ;
+ m_Origin.Move(a_AddMinX, a_AddMinY, a_AddMinZ);
+ m_Size.x -= a_AddMinX + a_SubMaxX;
+ m_Size.y -= a_AddMinY + a_SubMaxY;
+ m_Size.z -= a_AddMinZ + a_SubMaxZ;
}
@@ -571,12 +625,10 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
{
ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
}
- m_OriginX -= a_SubMinX;
- m_OriginY -= a_SubMinY;
- m_OriginZ -= a_SubMinZ;
- m_SizeX += a_SubMinX + a_AddMaxX;
- m_SizeY += a_SubMinY + a_AddMaxY;
- m_SizeZ += a_SubMinZ + a_AddMaxZ;
+ m_Origin.Move(-a_SubMinX, -a_SubMinY, -a_SubMinZ);
+ m_Size.x += a_SubMinX + a_AddMaxX;
+ m_Size.y += a_SubMinY + a_AddMaxY;
+ m_Size.z += a_SubMinZ + a_AddMaxZ;
}
@@ -626,7 +678,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorOverwrite
);
break;
@@ -641,7 +693,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorFillAir
);
break;
@@ -656,7 +708,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorImprint
);
break;
@@ -671,12 +723,57 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorLake
);
break;
} // case msLake
+ case msSpongePrint:
+ {
+ InternalMergeBlocks(
+ m_BlockTypes, a_Src.GetBlockTypes(),
+ DstMetas, SrcMetas,
+ SizeX, SizeY, SizeZ,
+ SrcOffX, SrcOffY, SrcOffZ,
+ DstOffX, DstOffY, DstOffZ,
+ a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
+ m_Size.x, m_Size.y, m_Size.z,
+ MergeCombinatorSpongePrint
+ );
+ break;
+ } // case msSpongePrint
+
+ case msDifference:
+ {
+ InternalMergeBlocks(
+ m_BlockTypes, a_Src.GetBlockTypes(),
+ DstMetas, SrcMetas,
+ SizeX, SizeY, SizeZ,
+ SrcOffX, SrcOffY, SrcOffZ,
+ DstOffX, DstOffY, DstOffZ,
+ a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
+ m_Size.x, m_Size.y, m_Size.z,
+ MergeCombinatorDifference
+ );
+ break;
+ } // case msDifference
+
+ case msMask:
+ {
+ InternalMergeBlocks(
+ m_BlockTypes, a_Src.GetBlockTypes(),
+ DstMetas, SrcMetas,
+ SizeX, SizeY, SizeZ,
+ SrcOffX, SrcOffY, SrcOffZ,
+ DstOffX, DstOffY, DstOffZ,
+ a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
+ m_Size.x, m_Size.y, m_Size.z,
+ MergeCombinatorMask
+ );
+ break;
+ } // case msMask
+
default:
{
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
@@ -963,17 +1060,17 @@ void cBlockArea::RotateCCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
+ int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]);
@@ -985,7 +1082,7 @@ void cBlockArea::RotateCCW(void)
delete[] NewTypes;
delete[] NewMetas;
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1008,17 +1105,17 @@ void cBlockArea::RotateCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int NewX = m_Size.z - z - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
- int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
+ int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]);
@@ -1030,7 +1127,7 @@ void cBlockArea::RotateCW(void)
delete[] NewTypes;
delete[] NewMetas;
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1053,13 +1150,13 @@ void cBlockArea::MirrorXY(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfZ = m_SizeZ / 2;
- int MaxZ = m_SizeZ - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int HalfZ = m_Size.z / 2;
+ int MaxZ = m_Size.z - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, y, MaxZ - z);
@@ -1093,13 +1190,13 @@ void cBlockArea::MirrorXZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfY = m_SizeY / 2;
- int MaxY = m_SizeY - 1;
+ int HalfY = m_Size.y / 2;
+ int MaxY = m_Size.y - 1;
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, MaxY - y, z);
@@ -1133,11 +1230,11 @@ void cBlockArea::MirrorYZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfX = m_SizeX / 2;
- int MaxX = m_SizeX - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int HalfX = m_Size.x / 2;
+ int MaxX = m_Size.x - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1161,16 +1258,16 @@ void cBlockArea::RotateCCWNoMeta(void)
{
if (HasBlockTypes())
{
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
+ NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
@@ -1179,23 +1276,23 @@ void cBlockArea::RotateCCWNoMeta(void)
}
if (HasBlockMetas())
{
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
+ NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1206,16 +1303,16 @@ void cBlockArea::RotateCWNoMeta(void)
{
if (HasBlockTypes())
{
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int z = 0; z < m_SizeZ; z++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int x = 0; x < m_SizeX; x++)
+ int NewX = m_Size.z - z - 1;
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
+ NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
@@ -1224,23 +1321,23 @@ void cBlockArea::RotateCWNoMeta(void)
}
if (HasBlockMetas())
{
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int z = 0; z < m_SizeZ; z++)
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int x = 0; x < m_SizeX; x++)
+ int NewX = m_Size.z - z - 1;
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
+ NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1249,15 +1346,15 @@ void cBlockArea::RotateCWNoMeta(void)
void cBlockArea::MirrorXYNoMeta(void)
{
- int HalfZ = m_SizeZ / 2;
- int MaxZ = m_SizeZ - 1;
+ int HalfZ = m_Size.z / 2;
+ int MaxZ = m_Size.z - 1;
if (HasBlockTypes())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]);
} // for x
@@ -1267,11 +1364,11 @@ void cBlockArea::MirrorXYNoMeta(void)
if (HasBlockMetas())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]);
} // for x
@@ -1286,15 +1383,15 @@ void cBlockArea::MirrorXYNoMeta(void)
void cBlockArea::MirrorXZNoMeta(void)
{
- int HalfY = m_SizeY / 2;
- int MaxY = m_SizeY - 1;
+ int HalfY = m_Size.y / 2;
+ int MaxY = m_Size.y - 1;
if (HasBlockTypes())
{
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]);
} // for x
@@ -1306,9 +1403,9 @@ void cBlockArea::MirrorXZNoMeta(void)
{
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]);
} // for x
@@ -1323,13 +1420,13 @@ void cBlockArea::MirrorXZNoMeta(void)
void cBlockArea::MirrorYZNoMeta(void)
{
- int HalfX = m_SizeX / 2;
- int MaxX = m_SizeX - 1;
+ int HalfX = m_Size.x / 2;
+ int MaxX = m_Size.x - 1;
if (HasBlockTypes())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1341,9 +1438,9 @@ void cBlockArea::MirrorYZNoMeta(void)
if (HasBlockMetas())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1374,7 +1471,7 @@ void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a
void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
{
- SetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType);
+ SetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType);
}
@@ -1451,7 +1548,7 @@ BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const
{
- return GetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ);
+ return GetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z);
}
@@ -1514,7 +1611,7 @@ NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ
void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- SetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
+ SetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@@ -1548,7 +1645,7 @@ void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, B
void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
{
- return GetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
+ return GetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@@ -1651,9 +1748,7 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
return false;
}
}
- m_SizeX = a_SizeX;
- m_SizeY = a_SizeY;
- m_SizeZ = a_SizeZ;
+ m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
return true;
}
@@ -1664,13 +1759,13 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const
{
ASSERT(a_RelX >= 0);
- ASSERT(a_RelX < m_SizeX);
+ ASSERT(a_RelX < m_Size.x);
ASSERT(a_RelY >= 0);
- ASSERT(a_RelY < m_SizeY);
+ ASSERT(a_RelY < m_Size.y);
ASSERT(a_RelZ >= 0);
- ASSERT(a_RelZ < m_SizeZ);
+ ASSERT(a_RelZ < m_Size.z);
- return a_RelX + a_RelZ * m_SizeX + a_RelY * m_SizeX * m_SizeZ;
+ return a_RelX + a_RelZ * m_Size.x + a_RelY * m_Size.x * m_Size.z;
}
@@ -1693,7 +1788,7 @@ void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_V
void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
{
- SetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Value, a_Array);
+ SetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Value, a_Array);
}
@@ -1716,7 +1811,7 @@ NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETY
NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const
{
- return GetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Array);
+ return GetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Array);
}
@@ -1729,9 +1824,7 @@ NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBL
cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
m_Area(a_Area),
- m_OriginX(a_Area.m_OriginX),
- m_OriginY(a_Area.m_OriginY),
- m_OriginZ(a_Area.m_OriginZ)
+ m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z)
{
}
@@ -1741,8 +1834,8 @@ cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc)
{
- int SizeY = m_Area.m_SizeY;
- int MinY = m_OriginY;
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@@ -1751,7 +1844,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@@ -1762,7 +1855,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
{
BaseX = 0;
}
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@@ -1774,13 +1867,13 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@@ -1824,8 +1917,8 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
return;
}
- int SizeY = m_Area.m_SizeY;
- int MinY = m_OriginY;
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@@ -1834,7 +1927,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@@ -1845,7 +1938,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
{
BaseX = 0;
}
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@@ -1857,13 +1950,13 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@@ -1983,21 +2076,21 @@ void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX
void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
- int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
- int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
- int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
+ int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
+ int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
+ int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
int OldIndex = 0;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
- for (int z = 0; z < m_SizeZ; z++)
+ int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
+ for (int z = 0; z < m_Size.z; z++)
{
- int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
+ int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
NewBlockTypes[idx++] = m_BlockTypes[OldIndex++];
} // for x
@@ -2013,21 +2106,21 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
- int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
- int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
- int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
+ int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
+ int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
+ int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
int OldIndex = 0;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
- for (int z = 0; z < m_SizeZ; z++)
+ int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
+ for (int z = 0; z < m_Size.z; z++)
{
- int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
+ int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
NewNibbles[idx++] = a_Array[OldIndex++];
} // for x
@@ -2038,6 +2131,9 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
}
+
+
+
void cBlockArea::RelSetData(
int a_RelX, int a_RelY, int a_RelZ,
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
diff --git a/src/BlockArea.h b/src/BlockArea.h
index 0703f195e..c48175b8c 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -13,13 +13,13 @@
#pragma once
#include "ForEachChunkProvider.h"
+#include "Vector3.h"
// fwd:
class cCuboid;
-class Vector3i;
@@ -43,12 +43,17 @@ public:
baSkyLight = 8,
} ;
+ /** The per-block strategy to use when merging another block area into this object.
+ See the Merge function for the description of these */
enum eMergeStrategy
{
msOverwrite,
msFillAir,
msImprint,
msLake,
+ msSpongePrint,
+ msDifference,
+ msMask,
} ;
cBlockArea(void);
@@ -57,12 +62,18 @@ public:
/** Clears the data stored to reclaim memory */
void Clear(void);
- /** Creates a new area of the specified size and contents.
- Origin is set to all zeroes.
+ /** Creates a new area of the specified size and contents.
+ Origin is set to all zeroes.
BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
*/
void Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes = baTypes | baMetas);
+ /** Creates a new area of the specified size and contents.
+ Origin is set to all zeroes.
+ BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
+ */
+ void Create(const Vector3i & a_Size, int a_DataTypes = baTypes | baMetas);
+
/** Resets the origin. No other changes are made, contents are untouched. */
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ);
@@ -119,8 +130,8 @@ public:
- msFillAir overwrites only those blocks that were air
- msImprint overwrites with only those blocks that are non-air
- Special strategies:
- msLake (evaluate top-down, first match wins):
+ Special strategies (evaluate top-down, first match wins):
+ msLake:
| area block | |
| this | Src | result |
+----------+--------+--------+
@@ -135,6 +146,22 @@ public:
| mycelium | stone | stone | ... and mycelium
| A | stone | A | ... but nothing else
| A | * | A | Everything else is left as it is
+
+ msSpongePrint:
+ Used for most generators, it allows carving out air pockets, too, and uses the Sponge as the NOP block
+ | area block | |
+ | this | Src | result |
+ +----------+--------+--------+
+ | A | sponge | A | Sponge is the NOP block
+ | * | B | B | Everything else overwrites anything
+
+ msMask:
+ Combines two areas, the blocks that are the same are kept, differing ones are reset to air
+ | area block | |
+ | this | Src | result |
+ +------+-------+--------+
+ | A | A | A | Same blocks are kept
+ | A | non-A | air | Everything else is replaced with air
*/
void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy);
@@ -209,6 +236,8 @@ public:
void SetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight);
void SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight);
void SetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight);
+ void SetWEOffset (int a_OffsetX, int a_OffsetY, int a_OffsetZ);
+ void SetWEOffset (const Vector3i & a_Offset);
// Getters:
BLOCKTYPE GetRelBlockType (int a_RelX, int a_RelY, int a_RelZ) const;
@@ -219,6 +248,7 @@ public:
NIBBLETYPE GetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
NIBBLETYPE GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
+ const Vector3i & GetWEOffset (void) const {return m_WEOffset;}
void SetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@@ -229,18 +259,24 @@ public:
void GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
void GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
+ // GetSize() is already exported manually to return 3 numbers, can't auto-export
+ const Vector3i & GetSize(void) const { return m_Size; }
+
+ // GetOrigin() is already exported manually to return 3 numbers, can't auto-export
+ const Vector3i & GetOrigin(void) const { return m_Origin; }
+
// tolua_begin
- int GetSizeX(void) const { return m_SizeX; }
- int GetSizeY(void) const { return m_SizeY; }
- int GetSizeZ(void) const { return m_SizeZ; }
+ int GetSizeX(void) const { return m_Size.x; }
+ int GetSizeY(void) const { return m_Size.y; }
+ int GetSizeZ(void) const { return m_Size.z; }
/** Returns the volume of the area, as number of blocks */
- int GetVolume(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
+ int GetVolume(void) const { return m_Size.x * m_Size.y * m_Size.z; }
- int GetOriginX(void) const { return m_OriginX; }
- int GetOriginY(void) const { return m_OriginY; }
- int GetOriginZ(void) const { return m_OriginZ; }
+ int GetOriginX(void) const { return m_Origin.x; }
+ int GetOriginY(void) const { return m_Origin.y; }
+ int GetOriginZ(void) const { return m_Origin.z; }
/** Returns the datatypes that are stored in the object (bitmask of baXXX values) */
int GetDataTypes(void) const;
@@ -258,7 +294,7 @@ public:
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
- int GetBlockCount(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
+ int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
protected:
@@ -273,9 +309,7 @@ protected:
protected:
cBlockArea & m_Area;
- int m_OriginX;
- int m_OriginY;
- int m_OriginZ;
+ Vector3i m_Origin;
int m_CurrentChunkX;
int m_CurrentChunkZ;
@@ -292,13 +326,13 @@ protected:
typedef NIBBLETYPE * NIBBLEARRAY;
- int m_OriginX;
- int m_OriginY;
- int m_OriginZ;
- int m_SizeX;
- int m_SizeY;
- int m_SizeZ;
+ Vector3i m_Origin;
+ Vector3i m_Size;
+ /** An extra data value sometimes stored in the .schematic file. Used mainly by the WorldEdit plugin.
+ cBlockArea doesn't use this value in any way. */
+ Vector3i m_WEOffset;
+
BLOCKTYPE * m_BlockTypes;
NIBBLETYPE * m_BlockMetas; // Each meta is stored as a separate byte for faster access
NIBBLETYPE * m_BlockLight; // Each light value is stored as a separate byte for faster access
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 57ad83de9..b42318c2f 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -10,6 +10,7 @@
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
+#include "FlowerPotEntity.h"
#include "FurnaceEntity.h"
#include "HopperEntity.h"
#include "JukeboxEntity.h"
@@ -30,6 +31,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
+ case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp
index d395997a6..96ca0ac37 100644
--- a/src/BlockEntities/CommandBlockEntity.cpp
+++ b/src/BlockEntities/CommandBlockEntity.cpp
@@ -160,7 +160,7 @@ bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value)
m_Command = a_Value.get("Command", "").asString();
m_LastOutput = a_Value.get("LastOutput", "").asString();
- m_Result = a_Value.get("SuccessCount", 0).asInt();
+ m_Result = (NIBBLETYPE)a_Value.get("SuccessCount", 0).asInt();
return true;
}
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index 374f3d6e3..e03bf776d 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -116,7 +116,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
+ m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
break;
@@ -138,6 +138,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break;
}
+ case E_ITEM_FIRE_CHARGE:
+ {
+ // TODO: Spawn fireball entity
+ break;
+ }
+
default:
{
DropFromSlot(a_Chunk, a_SlotNum);
diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp
new file mode 100644
index 000000000..87bf8b921
--- /dev/null
+++ b/src/BlockEntities/FlowerPotEntity.cpp
@@ -0,0 +1,134 @@
+
+// FlowerPotEntity.cpp
+
+// Implements the cFlowerPotEntity class representing a single sign in the world
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#include "json/json.h"
+#include "FlowerPotEntity.h"
+#include "../Entities/Player.h"
+#include "../Item.h"
+
+
+
+
+
+cFlowerPotEntity::cFlowerPotEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ super(E_BLOCK_FLOWER_POT, a_BlockX, a_BlockY, a_BlockZ, a_World)
+{
+}
+
+
+
+
+
+// It don't do anything when 'used'
+void cFlowerPotEntity::UsedBy(cPlayer * a_Player)
+{
+ if (IsItemInPot())
+ {
+ return;
+ }
+
+ cItem SelectedItem = a_Player->GetInventory().GetEquippedItem();
+ if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage))
+ {
+ m_Item = SelectedItem.CopyOne();
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ, a_Player->GetClientHandle());
+ }
+}
+
+
+
+
+
+void cFlowerPotEntity::SendTo(cClientHandle & a_Client)
+{
+ a_Client.SendUpdateBlockEntity(*this);
+}
+
+
+
+
+
+void cFlowerPotEntity::Destroy(void)
+{
+ // Drop the contents as pickups:
+ if (!m_Item.IsEmpty())
+ {
+ ASSERT(m_World != NULL);
+ cItems Pickups;
+ Pickups.Add(m_Item);
+ m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
+
+ m_Item.Empty();
+ }
+}
+
+
+
+
+
+bool cFlowerPotEntity::LoadFromJson(const Json::Value & a_Value)
+{
+ m_PosX = a_Value.get("x", 0).asInt();
+ m_PosY = a_Value.get("y", 0).asInt();
+ m_PosZ = a_Value.get("z", 0).asInt();
+
+ m_Item = cItem();
+ m_Item.FromJson(a_Value.get("Item", 0));
+
+ return true;
+}
+
+
+
+
+
+void cFlowerPotEntity::SaveToJson(Json::Value & a_Value)
+{
+ a_Value["x"] = m_PosX;
+ a_Value["y"] = m_PosY;
+ a_Value["z"] = m_PosZ;
+
+ Json::Value Item;
+ m_Item.GetJson(Item);
+ a_Value["Item"] = Item;
+}
+
+
+
+
+
+bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData)
+{
+ switch (m_ItemType)
+ {
+ case E_BLOCK_DANDELION:
+ case E_BLOCK_FLOWER:
+ case E_BLOCK_CACTUS:
+ case E_BLOCK_BROWN_MUSHROOM:
+ case E_BLOCK_RED_MUSHROOM:
+ case E_BLOCK_SAPLING:
+ case E_BLOCK_DEAD_BUSH:
+ {
+ return true;
+ }
+ case E_BLOCK_TALL_GRASS:
+ {
+ return (m_ItemData == (short) 2);
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+
+
+
diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h
new file mode 100644
index 000000000..da3fe9b7e
--- /dev/null
+++ b/src/BlockEntities/FlowerPotEntity.h
@@ -0,0 +1,74 @@
+// FlowerPotEntity.h
+
+// Declares the cFlowerPotEntity class representing a single sign in the world
+
+
+
+
+
+#pragma once
+
+#include "BlockEntity.h"
+
+class cItem;
+
+
+
+
+
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
+// tolua_begin
+
+class cFlowerPotEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity super;
+
+public:
+
+ // tolua_end
+
+ /** Creates a new flowerpot entity at the specified block coords. a_World may be NULL */
+ cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+ bool LoadFromJson( const Json::Value& a_Value );
+ virtual void SaveToJson(Json::Value& a_Value ) override;
+
+ virtual void Destroy(void) override;
+
+ // tolua_begin
+
+ /** Is a flower in the pot? */
+ bool IsItemInPot(void) { return !m_Item.IsEmpty(); }
+
+ /** Get the item in the flower pot */
+ cItem GetItem(void) const { return m_Item; }
+
+ /** Set the item in the flower pot */
+ void SetItem(const cItem a_Item) { m_Item = a_Item; }
+
+ // tolua_end
+
+ virtual void UsedBy(cPlayer * a_Player) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+
+ static bool IsFlower(short m_ItemType, short m_ItemData);
+
+ static const char * GetClassStatic(void) { return "cFlowerPotEntity"; }
+
+private:
+
+ cItem m_Item;
+} ; // tolua_export
+
+
+
+
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index af7043767..41fb9f811 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -219,7 +219,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_Pos.x + 0.5f, (float)m_Pos.y + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
- float Distance = (EntityPos - BlockPos).Length();
+ double Distance = (EntityPos - BlockPos).Length();
if (Distance < 0.5)
{
diff --git a/src/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h
index 01ce52494..3d1d604f7 100644
--- a/src/BlockEntities/JukeboxEntity.h
+++ b/src/BlockEntities/JukeboxEntity.h
@@ -38,10 +38,11 @@ public:
int GetRecord(void);
void SetRecord(int a_Record);
- /** Play a Record. Return false, when a_Record isn't a Record */
+ /** Plays the specified Record. Return false if a_Record isn't a playable Record (E_ITEM_XXX_DISC).
+ If there is a record already playing, ejects it first. */
bool PlayRecord(int a_Record);
- /** Ejects the currently held record as a pickup. Return false when no record inserted. */
+ /** Ejects the currently held record as a pickup. Return false when no record had been inserted. */
bool EjectRecord(void);
/** Is in the Jukebox a Record? */
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index ff1c54e3f..79e122032 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -12,20 +12,6 @@
-NIBBLETYPE g_BlockLightValue[256];
-NIBBLETYPE g_BlockSpreadLightFalloff[256];
-bool g_BlockTransparent[256];
-bool g_BlockOneHitDig[256];
-bool g_BlockPistonBreakable[256];
-bool g_BlockIsSnowable[256];
-bool g_BlockRequiresSpecialTool[256];
-bool g_BlockIsSolid[256];
-bool g_BlockFullyOccupiesVoxel[256];
-
-
-
-
-
class cBlockIDMap
{
// Making the map case-insensitive:
@@ -481,389 +467,4 @@ cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const char * a
-// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
-class cBlockPropertiesInitializer
-{
-public:
- cBlockPropertiesInitializer(void)
- {
- memset(g_BlockLightValue, 0x00, sizeof(g_BlockLightValue));
- memset(g_BlockSpreadLightFalloff, 0x0f, sizeof(g_BlockSpreadLightFalloff)); // 0x0f means total falloff
- memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent));
- memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig));
- memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable));
- memset(g_BlockFullyOccupiesVoxel, 0x00, sizeof(g_BlockFullyOccupiesVoxel));
-
- // Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
- for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++)
- {
- g_BlockIsSnowable[i] = true;
- }
- memset(g_BlockRequiresSpecialTool, 0x00, sizeof(g_BlockRequiresSpecialTool)); // Set all blocks to false
-
- // Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
- for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSolid); i++)
- {
- g_BlockIsSolid[i] = true;
- }
-
- // Emissive blocks
- g_BlockLightValue[E_BLOCK_FIRE] = 15;
- g_BlockLightValue[E_BLOCK_GLOWSTONE] = 15;
- g_BlockLightValue[E_BLOCK_JACK_O_LANTERN] = 15;
- g_BlockLightValue[E_BLOCK_LAVA] = 15;
- g_BlockLightValue[E_BLOCK_STATIONARY_LAVA] = 15;
- g_BlockLightValue[E_BLOCK_END_PORTAL] = 15;
- g_BlockLightValue[E_BLOCK_REDSTONE_LAMP_ON] = 15;
- g_BlockLightValue[E_BLOCK_TORCH] = 14;
- g_BlockLightValue[E_BLOCK_BURNING_FURNACE] = 13;
- g_BlockLightValue[E_BLOCK_NETHER_PORTAL] = 11;
- g_BlockLightValue[E_BLOCK_REDSTONE_ORE_GLOWING] = 9;
- g_BlockLightValue[E_BLOCK_REDSTONE_REPEATER_ON] = 9;
- g_BlockLightValue[E_BLOCK_REDSTONE_TORCH_ON] = 7;
- g_BlockLightValue[E_BLOCK_BREWING_STAND] = 1;
- g_BlockLightValue[E_BLOCK_BROWN_MUSHROOM] = 1;
- g_BlockLightValue[E_BLOCK_DRAGON_EGG] = 1;
-
- // Spread blocks
- g_BlockSpreadLightFalloff[E_BLOCK_AIR] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_CAKE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_CHEST] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_COBWEB] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_CROPS] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_FENCE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_FENCE_GATE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_FIRE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_GLASS] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_GLASS_PANE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_GLOWSTONE] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_IRON_BARS] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_IRON_DOOR] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_LEAVES] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_SIGN_POST] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_TORCH] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_VINES] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_WALLSIGN] = 1;
- g_BlockSpreadLightFalloff[E_BLOCK_WOODEN_DOOR] = 1;
-
- // Light in water and lava dissapears faster:
- g_BlockSpreadLightFalloff[E_BLOCK_LAVA] = 3;
- g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_LAVA] = 3;
- g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_WATER] = 3;
- g_BlockSpreadLightFalloff[E_BLOCK_WATER] = 3;
-
- // Transparent blocks
- g_BlockTransparent[E_BLOCK_ACTIVATOR_RAIL] = true;
- g_BlockTransparent[E_BLOCK_AIR] = true;
- g_BlockTransparent[E_BLOCK_BIG_FLOWER] = true;
- g_BlockTransparent[E_BLOCK_BROWN_MUSHROOM] = true;
- g_BlockTransparent[E_BLOCK_CARROTS] = true;
- g_BlockTransparent[E_BLOCK_CHEST] = true;
- g_BlockTransparent[E_BLOCK_COBWEB] = true;
- g_BlockTransparent[E_BLOCK_CROPS] = true;
- g_BlockTransparent[E_BLOCK_DANDELION] = true;
- g_BlockTransparent[E_BLOCK_DETECTOR_RAIL] = true;
- g_BlockTransparent[E_BLOCK_ENDER_CHEST] = true;
- g_BlockTransparent[E_BLOCK_FENCE] = true;
- g_BlockTransparent[E_BLOCK_FENCE_GATE] = true;
- g_BlockTransparent[E_BLOCK_FIRE] = true;
- g_BlockTransparent[E_BLOCK_FLOWER] = true;
- g_BlockTransparent[E_BLOCK_FLOWER_POT] = true;
- g_BlockTransparent[E_BLOCK_GLASS] = true;
- g_BlockTransparent[E_BLOCK_GLASS_PANE] = true;
- g_BlockTransparent[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockTransparent[E_BLOCK_ICE] = true;
- g_BlockTransparent[E_BLOCK_IRON_DOOR] = true;
- g_BlockTransparent[E_BLOCK_LAVA] = true;
- g_BlockTransparent[E_BLOCK_LEAVES] = true;
- g_BlockTransparent[E_BLOCK_LEVER] = true;
- g_BlockTransparent[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockTransparent[E_BLOCK_MELON_STEM] = true;
- g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true;
- g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true;
- g_BlockTransparent[E_BLOCK_POTATOES] = true;
- g_BlockTransparent[E_BLOCK_POWERED_RAIL] = true;
- g_BlockTransparent[E_BLOCK_PISTON_EXTENSION] = true;
- g_BlockTransparent[E_BLOCK_PUMPKIN_STEM] = true;
- g_BlockTransparent[E_BLOCK_RAIL] = true;
- g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true;
- g_BlockTransparent[E_BLOCK_SIGN_POST] = true;
- g_BlockTransparent[E_BLOCK_SNOW] = true;
- g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true;
- g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true;
- g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true;
- g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true;
- g_BlockTransparent[E_BLOCK_STONE_BUTTON] = true;
- g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true;
- g_BlockTransparent[E_BLOCK_TALL_GRASS] = true;
- g_BlockTransparent[E_BLOCK_TORCH] = true;
- g_BlockTransparent[E_BLOCK_VINES] = true;
- g_BlockTransparent[E_BLOCK_WALLSIGN] = true;
- g_BlockTransparent[E_BLOCK_WATER] = true;
- g_BlockTransparent[E_BLOCK_WOODEN_BUTTON] = true;
- g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true;
- g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
-
- // TODO: Any other transparent blocks?
-
- // One hit break blocks:
- g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true;
- g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true;
- g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true;
- g_BlockOneHitDig[E_BLOCK_CARROTS] = true;
- g_BlockOneHitDig[E_BLOCK_CROPS] = true;
- g_BlockOneHitDig[E_BLOCK_DANDELION] = true;
- g_BlockOneHitDig[E_BLOCK_FIRE] = true;
- g_BlockOneHitDig[E_BLOCK_FLOWER] = true;
- g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true;
- g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true;
- g_BlockOneHitDig[E_BLOCK_MELON_STEM] = true;
- g_BlockOneHitDig[E_BLOCK_POTATOES] = true;
- g_BlockOneHitDig[E_BLOCK_PUMPKIN_STEM] = true;
- g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
- g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_ON] = true;
- g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_OFF] = true;
- g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_ON] = true;
- g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true;
- g_BlockOneHitDig[E_BLOCK_RED_MUSHROOM] = true;
- g_BlockOneHitDig[E_BLOCK_REEDS] = true;
- g_BlockOneHitDig[E_BLOCK_SAPLING] = true;
- g_BlockOneHitDig[E_BLOCK_TNT] = true;
- g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true;
- g_BlockOneHitDig[E_BLOCK_TORCH] = true;
-
- // Blocks that break when pushed by piston:
- g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true;
- g_BlockPistonBreakable[E_BLOCK_AIR] = true;
- g_BlockPistonBreakable[E_BLOCK_BED] = true;
- g_BlockPistonBreakable[E_BLOCK_BIG_FLOWER] = true;
- g_BlockPistonBreakable[E_BLOCK_BROWN_MUSHROOM] = true;
- g_BlockPistonBreakable[E_BLOCK_COBWEB] = true;
- g_BlockPistonBreakable[E_BLOCK_CROPS] = true;
- g_BlockPistonBreakable[E_BLOCK_DANDELION] = true;
- g_BlockPistonBreakable[E_BLOCK_DEAD_BUSH] = true;
- g_BlockPistonBreakable[E_BLOCK_FIRE] = true;
- g_BlockPistonBreakable[E_BLOCK_FLOWER] = true;
- g_BlockPistonBreakable[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockPistonBreakable[E_BLOCK_INACTIVE_COMPARATOR] = true;
- g_BlockPistonBreakable[E_BLOCK_IRON_DOOR] = true;
- g_BlockPistonBreakable[E_BLOCK_JACK_O_LANTERN] = true;
- g_BlockPistonBreakable[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockPistonBreakable[E_BLOCK_LADDER] = true;
- g_BlockPistonBreakable[E_BLOCK_LAVA] = true;
- g_BlockPistonBreakable[E_BLOCK_LEVER] = true;
- g_BlockPistonBreakable[E_BLOCK_MELON] = true;
- g_BlockPistonBreakable[E_BLOCK_MELON_STEM] = true;
- g_BlockPistonBreakable[E_BLOCK_PUMPKIN] = true;
- g_BlockPistonBreakable[E_BLOCK_PUMPKIN_STEM] = true;
- g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
- g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_ON] = true;
- g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_OFF] = true;
- g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_ON] = true;
- g_BlockPistonBreakable[E_BLOCK_REDSTONE_WIRE] = true;
- g_BlockPistonBreakable[E_BLOCK_RED_MUSHROOM] = true;
- g_BlockPistonBreakable[E_BLOCK_REEDS] = true;
- g_BlockPistonBreakable[E_BLOCK_SNOW] = true;
- g_BlockPistonBreakable[E_BLOCK_STATIONARY_LAVA] = true;
- g_BlockPistonBreakable[E_BLOCK_STATIONARY_WATER] = true;
- g_BlockPistonBreakable[E_BLOCK_STONE_BUTTON] = true;
- g_BlockPistonBreakable[E_BLOCK_STONE_PRESSURE_PLATE] = true;
- g_BlockPistonBreakable[E_BLOCK_TALL_GRASS] = true;
- g_BlockPistonBreakable[E_BLOCK_TORCH] = true;
- g_BlockPistonBreakable[E_BLOCK_VINES] = true;
- g_BlockPistonBreakable[E_BLOCK_WATER] = true;
- g_BlockPistonBreakable[E_BLOCK_WOODEN_BUTTON] = true;
- g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true;
- g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
-
-
- // Blocks that cannot be snowed over:
- g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false;
- g_BlockIsSnowable[E_BLOCK_AIR] = false;
- g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false;
- g_BlockIsSnowable[E_BLOCK_BROWN_MUSHROOM] = false;
- g_BlockIsSnowable[E_BLOCK_CACTUS] = false;
- g_BlockIsSnowable[E_BLOCK_CHEST] = false;
- g_BlockIsSnowable[E_BLOCK_CROPS] = false;
- g_BlockIsSnowable[E_BLOCK_DANDELION] = false;
- g_BlockIsSnowable[E_BLOCK_FIRE] = false;
- g_BlockIsSnowable[E_BLOCK_FLOWER] = false;
- g_BlockIsSnowable[E_BLOCK_GLASS] = false;
- g_BlockIsSnowable[E_BLOCK_ICE] = false;
- g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false;
- g_BlockIsSnowable[E_BLOCK_LAVA] = false;
- g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false;
- g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false;
- g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false;
- g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_OFF] = false;
- g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_ON] = false;
- g_BlockIsSnowable[E_BLOCK_REDSTONE_WIRE] = false;
- g_BlockIsSnowable[E_BLOCK_RED_MUSHROOM] = false;
- g_BlockIsSnowable[E_BLOCK_REEDS] = false;
- g_BlockIsSnowable[E_BLOCK_SAPLING] = false;
- g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false;
- g_BlockIsSnowable[E_BLOCK_SNOW] = false;
- g_BlockIsSnowable[E_BLOCK_STAINED_GLASS] = false;
- g_BlockIsSnowable[E_BLOCK_STAINED_GLASS_PANE] = false;
- g_BlockIsSnowable[E_BLOCK_STATIONARY_LAVA] = false;
- g_BlockIsSnowable[E_BLOCK_STATIONARY_WATER] = false;
- g_BlockIsSnowable[E_BLOCK_TALL_GRASS] = false;
- g_BlockIsSnowable[E_BLOCK_TNT] = false;
- g_BlockIsSnowable[E_BLOCK_TORCH] = false;
- g_BlockIsSnowable[E_BLOCK_VINES] = false;
- g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false;
- g_BlockIsSnowable[E_BLOCK_WATER] = false;
-
-
- // Blocks that don't drop without a special tool:
- g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_CAULDRON] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE_STAIRS] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_COBWEB] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_BLOCK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_DOUBLE_STONE_SLAB] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_EMERALD_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_END_STONE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_GOLD_BLOCK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_GOLD_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_IRON_BLOCK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_IRON_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_BLOCK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_MOSSY_COBBLESTONE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_NETHERRACK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK_STAIRS] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_OBSIDIAN] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE_STAIRS] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_SNOW] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_STONE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICKS] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICK_STAIRS] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_STONE_PRESSURE_PLATE] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true;
- g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true;
-
- // Nonsolid blocks:
- g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false;
- g_BlockIsSolid[E_BLOCK_AIR] = false;
- g_BlockIsSolid[E_BLOCK_BIG_FLOWER] = false;
- g_BlockIsSolid[E_BLOCK_BROWN_MUSHROOM] = false;
- g_BlockIsSolid[E_BLOCK_CARROTS] = false;
- g_BlockIsSolid[E_BLOCK_COBWEB] = false;
- g_BlockIsSolid[E_BLOCK_CROPS] = false;
- g_BlockIsSolid[E_BLOCK_DANDELION] = false;
- g_BlockIsSolid[E_BLOCK_DETECTOR_RAIL] = false;
- g_BlockIsSolid[E_BLOCK_END_PORTAL] = false;
- g_BlockIsSolid[E_BLOCK_FIRE] = false;
- g_BlockIsSolid[E_BLOCK_FLOWER] = false;
- g_BlockIsSolid[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = false;
- g_BlockIsSolid[E_BLOCK_LAVA] = false;
- g_BlockIsSolid[E_BLOCK_LEVER] = false;
- g_BlockIsSolid[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = false;
- g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
- g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
- g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
- g_BlockIsSolid[E_BLOCK_POTATOES] = false;
- g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
- g_BlockIsSolid[E_BLOCK_RAIL] = false;
- g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
- g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false;
- g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false;
- g_BlockIsSolid[E_BLOCK_RED_MUSHROOM] = false;
- g_BlockIsSolid[E_BLOCK_REEDS] = false;
- g_BlockIsSolid[E_BLOCK_SAPLING] = false;
- g_BlockIsSolid[E_BLOCK_SIGN_POST] = false;
- g_BlockIsSolid[E_BLOCK_SNOW] = false;
- g_BlockIsSolid[E_BLOCK_STATIONARY_LAVA] = false;
- g_BlockIsSolid[E_BLOCK_STATIONARY_WATER] = false;
- g_BlockIsSolid[E_BLOCK_STONE_BUTTON] = false;
- g_BlockIsSolid[E_BLOCK_STONE_PRESSURE_PLATE] = false;
- g_BlockIsSolid[E_BLOCK_TALL_GRASS] = false;
- g_BlockIsSolid[E_BLOCK_TORCH] = false;
- g_BlockIsSolid[E_BLOCK_TRIPWIRE] = false;
- g_BlockIsSolid[E_BLOCK_VINES] = false;
- g_BlockIsSolid[E_BLOCK_WALLSIGN] = false;
- g_BlockIsSolid[E_BLOCK_WATER] = false;
- g_BlockIsSolid[E_BLOCK_WOODEN_BUTTON] = false;
- g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false;
- g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false;
-
- // Torch placeable blocks:
- g_BlockFullyOccupiesVoxel[E_BLOCK_NEW_LOG] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_BEDROCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_COAL] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_REDSTONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_BOOKCASE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_BRICK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_CLAY] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_COAL_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_COBBLESTONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_COMMAND_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_CRAFTING_TABLE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DIRT] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DISPENSER] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_STONE_SLAB] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_WOODEN_SLAB] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_DROPPER] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_END_STONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_FURNACE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_GLOWSTONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_GRASS] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_GRAVEL] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_HARDENED_CLAY] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_HAY_BALE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_BROWN_MUSHROOM] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_RED_MUSHROOM] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_JACK_O_LANTERN] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_JUKEBOX] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_LOG] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_MELON] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_MOSSY_COBBLESTONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_MYCELIUM] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_NETHERRACK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_BRICK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_QUARTZ_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_NOTE_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_OBSIDIAN] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_PACKED_ICE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_PLANKS] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_PUMPKIN] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_QUARTZ_BLOCK] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_OFF] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_ON] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_SANDSTONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_SAND] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_SILVERFISH_EGG] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_SPONGE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_STAINED_CLAY] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_WOOL] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_STONE] = true;
- g_BlockFullyOccupiesVoxel[E_BLOCK_STONE_BRICKS] = true;
- }
-} BlockPropertiesInitializer;
-
-
-
-
diff --git a/src/BlockID.h b/src/BlockID.h
index 861bb8dae..2fec512e2 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -853,9 +853,30 @@ enum eExplosionSource
esWitherSkullBlue,
esWitherBirth,
esPlugin,
-
- // Obsolete constants, kept for compatibility, will be removed after some time:
- esCreeper = esMonster,
+} ;
+
+
+
+
+
+enum eShrapnelLevel
+{
+ slNone,
+ slGravityAffectedOnly,
+ slAll
+} ;
+
+
+
+
+
+enum eSpreadSource
+{
+ ssFireSpread,
+ ssGrassSpread,
+ ssMushroomSpread,
+ ssMycelSpread,
+ ssVineSpread,
} ;
// tolua_end
@@ -909,17 +930,3 @@ extern cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const c
-// Block properties:
-extern NIBBLETYPE g_BlockLightValue[256];
-extern NIBBLETYPE g_BlockSpreadLightFalloff[256];
-extern bool g_BlockTransparent[256];
-extern bool g_BlockOneHitDig[256];
-extern bool g_BlockPistonBreakable[256];
-extern bool g_BlockIsSnowable[256];
-extern bool g_BlockRequiresSpecialTool[256];
-extern bool g_BlockIsSolid[256];
-extern bool g_BlockFullyOccupiesVoxel[256];
-
-
-
-
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
new file mode 100644
index 000000000..6fb5aa5b3
--- /dev/null
+++ b/src/BlockInfo.cpp
@@ -0,0 +1,451 @@
+
+#include "Globals.h"
+
+#include "BlockInfo.h"
+#include "Blocks/BlockHandler.h"
+
+
+
+
+
+cBlockInfo cBlockInfo::ms_Info[256];
+
+
+
+
+
+cBlockInfo::cBlockInfo()
+ : m_LightValue(0x00)
+ , m_SpreadLightFalloff(0x0f)
+ , m_Transparent(false)
+ , m_OneHitDig(false)
+ , m_PistonBreakable(false)
+ , m_IsSnowable(true)
+ , m_RequiresSpecialTool(false)
+ , m_IsSolid(true)
+ , m_FullyOccupiesVoxel(false)
+ , m_Handler(NULL)
+{}
+
+
+
+
+
+cBlockInfo::~cBlockInfo()
+{
+ delete m_Handler;
+}
+
+
+
+
+
+cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
+{
+ return ms_Info[a_Type];
+}
+
+
+
+
+
+void cBlockInfo::Initialize(void)
+{
+ for (unsigned int i = 0; i < 256; ++i)
+ {
+ if (ms_Info[i].m_Handler == NULL)
+ {
+ ms_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i);
+ }
+ }
+
+ // Emissive blocks
+ ms_Info[E_BLOCK_FIRE ].m_LightValue = 15;
+ ms_Info[E_BLOCK_GLOWSTONE ].m_LightValue = 15;
+ ms_Info[E_BLOCK_JACK_O_LANTERN ].m_LightValue = 15;
+ ms_Info[E_BLOCK_LAVA ].m_LightValue = 15;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_LightValue = 15;
+ ms_Info[E_BLOCK_END_PORTAL ].m_LightValue = 15;
+ ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_LightValue = 15;
+ ms_Info[E_BLOCK_TORCH ].m_LightValue = 14;
+ ms_Info[E_BLOCK_BURNING_FURNACE ].m_LightValue = 13;
+ ms_Info[E_BLOCK_NETHER_PORTAL ].m_LightValue = 11;
+ ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_LightValue = 9;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_LightValue = 9;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_LightValue = 7;
+ ms_Info[E_BLOCK_BREWING_STAND ].m_LightValue = 1;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_LightValue = 1;
+ ms_Info[E_BLOCK_DRAGON_EGG ].m_LightValue = 1;
+
+
+ // Spread blocks
+ ms_Info[E_BLOCK_AIR ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_CAKE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_CHEST ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_COBWEB ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_CROPS ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_FENCE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_FENCE_GATE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_FIRE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_GLASS ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_GLASS_PANE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_GLOWSTONE ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_WALLSIGN ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_WOODEN_DOOR ].m_SpreadLightFalloff = 1;
+
+ // Light in water and lava dissapears faster:
+ ms_Info[E_BLOCK_LAVA ].m_SpreadLightFalloff = 3;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_SpreadLightFalloff = 3;
+ ms_Info[E_BLOCK_STATIONARY_WATER ].m_SpreadLightFalloff = 3;
+ ms_Info[E_BLOCK_WATER ].m_SpreadLightFalloff = 3;
+
+
+ // Transparent blocks
+ ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true;
+ ms_Info[E_BLOCK_AIR ].m_Transparent = true;
+ ms_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true;
+ ms_Info[E_BLOCK_CARROTS ].m_Transparent = true;
+ ms_Info[E_BLOCK_CHEST ].m_Transparent = true;
+ ms_Info[E_BLOCK_COBWEB ].m_Transparent = true;
+ ms_Info[E_BLOCK_CROPS ].m_Transparent = true;
+ ms_Info[E_BLOCK_DANDELION ].m_Transparent = true;
+ ms_Info[E_BLOCK_DETECTOR_RAIL ].m_Transparent = true;
+ ms_Info[E_BLOCK_ENDER_CHEST ].m_Transparent = true;
+ ms_Info[E_BLOCK_FENCE ].m_Transparent = true;
+ ms_Info[E_BLOCK_FENCE_GATE ].m_Transparent = true;
+ ms_Info[E_BLOCK_FIRE ].m_Transparent = true;
+ ms_Info[E_BLOCK_FLOWER ].m_Transparent = true;
+ ms_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true;
+ ms_Info[E_BLOCK_GLASS ].m_Transparent = true;
+ ms_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true;
+ ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
+ ms_Info[E_BLOCK_ICE ].m_Transparent = true;
+ ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
+ ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
+ ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
+ ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
+ ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
+ ms_Info[E_BLOCK_MELON_STEM ].m_Transparent = true;
+ ms_Info[E_BLOCK_NETHER_BRICK_FENCE ].m_Transparent = true;
+ ms_Info[E_BLOCK_NEW_LEAVES ].m_Transparent = true;
+ ms_Info[E_BLOCK_POTATOES ].m_Transparent = true;
+ ms_Info[E_BLOCK_POWERED_RAIL ].m_Transparent = true;
+ ms_Info[E_BLOCK_PISTON_EXTENSION ].m_Transparent = true;
+ ms_Info[E_BLOCK_PUMPKIN_STEM ].m_Transparent = true;
+ ms_Info[E_BLOCK_RAIL ].m_Transparent = true;
+ ms_Info[E_BLOCK_RED_MUSHROOM ].m_Transparent = true;
+ ms_Info[E_BLOCK_SIGN_POST ].m_Transparent = true;
+ ms_Info[E_BLOCK_SNOW ].m_Transparent = true;
+ ms_Info[E_BLOCK_STAINED_GLASS ].m_Transparent = true;
+ ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_Transparent = true;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_Transparent = true;
+ ms_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true;
+ ms_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true;
+ ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true;
+ ms_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true;
+ ms_Info[E_BLOCK_TORCH ].m_Transparent = true;
+ ms_Info[E_BLOCK_VINES ].m_Transparent = true;
+ ms_Info[E_BLOCK_WALLSIGN ].m_Transparent = true;
+ ms_Info[E_BLOCK_WATER ].m_Transparent = true;
+ ms_Info[E_BLOCK_WOODEN_BUTTON ].m_Transparent = true;
+ ms_Info[E_BLOCK_WOODEN_DOOR ].m_Transparent = true;
+ ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_Transparent = true;
+
+ // TODO: Any other transparent blocks?
+
+
+ // One hit break blocks:
+ ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_BIG_FLOWER ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_CARROTS ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_CROPS ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_DANDELION ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_FIRE ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_FLOWER ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_FLOWER_POT ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_MELON_STEM ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_POTATOES ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_PUMPKIN_STEM ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REDSTONE_WIRE ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_RED_MUSHROOM ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_REEDS ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_SAPLING ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_TNT ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_TALL_GRASS ].m_OneHitDig = true;
+ ms_Info[E_BLOCK_TORCH ].m_OneHitDig = true;
+
+
+ // Blocks that break when pushed by piston:
+ ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_AIR ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_BED ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_CROPS ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_FIRE ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_JACK_O_LANTERN ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_LADDER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_LAVA ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_LEVER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_MELON ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_MELON_STEM ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_PUMPKIN ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_PUMPKIN_STEM ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REDSTONE_WIRE ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_RED_MUSHROOM ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_REEDS ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_SNOW ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_STATIONARY_WATER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_STONE_BUTTON ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_TALL_GRASS ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_TORCH ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_VINES ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_WATER ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_WOODEN_BUTTON ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_WOODEN_DOOR ].m_PistonBreakable = true;
+ ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_PistonBreakable = true;
+
+
+ // Blocks that cannot be snowed over:
+ ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_AIR ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_CACTUS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_CHEST ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_CROPS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_DANDELION ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_FIRE ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_FLOWER ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_GLASS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_ICE ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_LAVA ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_LILY_PAD ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_REEDS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_SAPLING ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_SIGN_POST ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_SNOW ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_STAINED_GLASS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_TNT ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_TORCH ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_VINES ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_WALLSIGN ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_WATER ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false;
+
+
+ // Blocks that don't drop without a special tool:
+ ms_Info[E_BLOCK_BRICK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_DIAMOND_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_EMERALD_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_END_STONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_GOLD_BLOCK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_GOLD_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_IRON_BLOCK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_IRON_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_LAPIS_BLOCK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_LAPIS_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_NETHERRACK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_NETHER_BRICK ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_NETHER_BRICK_STAIRS ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_OBSIDIAN ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_REDSTONE_ORE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_SANDSTONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_SANDSTONE_STAIRS ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_SNOW ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_STONE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_STONE_BRICKS ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_STONE_BRICK_STAIRS ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_STONE_SLAB ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_FURNACE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_LIT_FURNACE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_ANVIL ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_RequiresSpecialTool = true;
+
+
+ // Nonsolid blocks:
+ ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_AIR ].m_IsSolid = false;
+ ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false;
+ ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false;
+ ms_Info[E_BLOCK_CARROTS ].m_IsSolid = false;
+ ms_Info[E_BLOCK_COBWEB ].m_IsSolid = false;
+ ms_Info[E_BLOCK_CROPS ].m_IsSolid = false;
+ ms_Info[E_BLOCK_DANDELION ].m_IsSolid = false;
+ ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_FIRE ].m_IsSolid = false;
+ ms_Info[E_BLOCK_FLOWER ].m_IsSolid = false;
+ ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
+ ms_Info[E_BLOCK_LAVA ].m_IsSolid = false;
+ ms_Info[E_BLOCK_LEVER ].m_IsSolid = false;
+ ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
+ ms_Info[E_BLOCK_MELON_STEM ].m_IsSolid = false;
+ ms_Info[E_BLOCK_NETHER_PORTAL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_PISTON_EXTENSION ].m_IsSolid = false;
+ ms_Info[E_BLOCK_POTATOES ].m_IsSolid = false;
+ ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_RAIL ].m_IsSolid = false;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSolid = false;
+ ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSolid = false;
+ ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSolid = false;
+ ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false;
+ ms_Info[E_BLOCK_REEDS ].m_IsSolid = false;
+ ms_Info[E_BLOCK_SAPLING ].m_IsSolid = false;
+ ms_Info[E_BLOCK_SIGN_POST ].m_IsSolid = false;
+ ms_Info[E_BLOCK_SNOW ].m_IsSolid = false;
+ ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false;
+ ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false;
+ ms_Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false;
+ ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_IsSolid = false;
+ ms_Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false;
+ ms_Info[E_BLOCK_TORCH ].m_IsSolid = false;
+ ms_Info[E_BLOCK_TRIPWIRE ].m_IsSolid = false;
+ ms_Info[E_BLOCK_VINES ].m_IsSolid = false;
+ ms_Info[E_BLOCK_WALLSIGN ].m_IsSolid = false;
+ ms_Info[E_BLOCK_WATER ].m_IsSolid = false;
+ ms_Info[E_BLOCK_WOODEN_BUTTON ].m_IsSolid = false;
+ ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_IsSolid = false;
+ ms_Info[E_BLOCK_WOODEN_SLAB ].m_IsSolid = false;
+
+
+ // Blocks that fully occupy their voxel - used as a guide for torch placeable blocks, amongst other things:
+ ms_Info[E_BLOCK_NEW_LOG ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_BLOCK_OF_COAL ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_BLOCK_OF_REDSTONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_BOOKCASE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_BRICK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_CLAY ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_COAL_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_COBBLESTONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_COMMAND_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_CRAFTING_TABLE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DIAMOND_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DIRT ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DISPENSER ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_DROPPER ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_EMERALD_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_EMERALD_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_END_STONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_FURNACE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_GLOWSTONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_GOLD_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_GOLD_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_GRASS ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_GRAVEL ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_HARDENED_CLAY ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_HAY_BALE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_ICE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_IRON_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_IRON_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_JACK_O_LANTERN ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_JUKEBOX ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_LAPIS_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_NETHER_BRICK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_NETHER_QUARTZ_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_NOTE_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_OBSIDIAN ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_PACKED_ICE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_PLANKS ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_PUMPKIN ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_QUARTZ_BLOCK ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_REDSTONE_ORE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_SANDSTONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_SAND ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_SILVERFISH_EGG ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_SPONGE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_STAINED_CLAY ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_WOOL ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_STONE ].m_FullyOccupiesVoxel = true;
+ ms_Info[E_BLOCK_STONE_BRICKS ].m_FullyOccupiesVoxel = true;
+}
+
+
+
+
+
+// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
+class cBlockInfoInitializer
+{
+public:
+ cBlockInfoInitializer(void)
+ {
+ cBlockInfo::Initialize();
+ }
+} BlockInfoInitializer;
+
+
+
+
+
diff --git a/src/BlockInfo.h b/src/BlockInfo.h
new file mode 100644
index 000000000..40c1db867
--- /dev/null
+++ b/src/BlockInfo.h
@@ -0,0 +1,103 @@
+
+#pragma once
+
+
+
+
+
+// fwd:
+class cBlockHandler;
+
+
+
+
+
+// tolua_begin
+class cBlockInfo
+{
+public:
+ // tolua_end
+
+ cBlockInfo();
+
+ ~cBlockInfo();
+
+ /** (Re-)Initializes the internal BlockInfo structures. */
+ static void Initialize(void);
+
+ // tolua_begin
+
+ /** Returns the associated BlockInfo structure. */
+ static cBlockInfo & Get(BLOCKTYPE a_Type);
+
+
+ /** How much light do the blocks emit on their own? */
+ NIBBLETYPE m_LightValue;
+
+ /** How much light do the blocks consume? */
+ NIBBLETYPE m_SpreadLightFalloff;
+
+ /** Is a block completely transparent? (light doesn't get decreased(?)) */
+ bool m_Transparent;
+
+ /** Is a block destroyed after a single hit? */
+ bool m_OneHitDig;
+
+ /** Can a piston break this block? */
+ bool m_PistonBreakable;
+
+ /** Can this block hold snow atop? */
+ bool m_IsSnowable;
+
+ /** Does this block require a tool to drop? */
+ bool m_RequiresSpecialTool;
+
+ /** Is this block solid (player cannot walk through)? */
+ bool m_IsSolid;
+
+ /** Does this block fully occupy its voxel - is it a 'full' block? */
+ bool m_FullyOccupiesVoxel;
+
+ // tolua_end
+
+ /** Associated block handler. */
+ cBlockHandler * m_Handler;
+
+ // tolua_begin
+
+ inline static NIBBLETYPE GetLightValue (BLOCKTYPE a_Type) { return Get(a_Type).m_LightValue; }
+ inline static NIBBLETYPE GetSpreadLightFalloff(BLOCKTYPE a_Type) { return Get(a_Type).m_SpreadLightFalloff; }
+ inline static bool IsTransparent (BLOCKTYPE a_Type) { return Get(a_Type).m_Transparent; }
+ inline static bool IsOneHitDig (BLOCKTYPE a_Type) { return Get(a_Type).m_OneHitDig; }
+ inline static bool IsPistonBreakable (BLOCKTYPE a_Type) { return Get(a_Type).m_PistonBreakable; }
+ inline static bool IsSnowable (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSnowable; }
+ inline static bool RequiresSpecialTool (BLOCKTYPE a_Type) { return Get(a_Type).m_RequiresSpecialTool; }
+ inline static bool IsSolid (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSolid; }
+ inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; }
+
+ // tolua_end
+
+ inline static cBlockHandler * GetHandler (BLOCKTYPE a_Type) { return Get(a_Type).m_Handler; }
+
+
+protected:
+
+ // TODO xdot: Change to std::vector to support dynamic block IDs
+ static cBlockInfo ms_Info[256];
+
+
+}; // tolua_export
+
+
+
+
+
+// Shortcut to get the blockhandler for a specific block
+inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
+{
+ return cBlockInfo::Get(a_BlockType).m_Handler;
+}
+
+
+
+
diff --git a/src/BlockTracer.h b/src/BlockTracer.h
index 40d80da1a..a18c8df4d 100644
--- a/src/BlockTracer.h
+++ b/src/BlockTracer.h
@@ -28,6 +28,9 @@ public:
class cCallbacks abstract
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted.
*/
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
new file mode 100644
index 000000000..93a796ef7
--- /dev/null
+++ b/src/Blocks/BlockAnvil.h
@@ -0,0 +1,61 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBlockAnvilHandler :
+ public cBlockHandler
+{
+public:
+ cBlockAnvilHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = m_BlockType;
+ NIBBLETYPE HighBits = a_BlockMeta & 0x0c; // Only highest two bits are preserved
+ int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3;
+ switch (Direction)
+ {
+ case 0: a_BlockMeta = 0x2 | HighBits; break;
+ case 1: a_BlockMeta = 0x3 | HighBits; break;
+ case 2: a_BlockMeta = 0x0 | HighBits; break;
+ case 3: a_BlockMeta = 0x1 | HighBits; break;
+ default:
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ virtual bool IsUseable() override
+ {
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index 3dad4feba..6a3c6a55b 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -51,6 +51,49 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
+class cTimeFastForwardTester :
+ public cPlayerListCallback
+{
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ if (!a_Player->IsInBed())
+ {
+ return true;
+ }
+
+ return false;
+ }
+};
+
+
+
+
+
+class cPlayerBedStateUnsetter :
+ public cPlayerListCallback
+{
+public:
+ cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
+ m_Position(a_Position), m_WorldInterface(a_WorldInterface)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ a_Player->SetIsInBed(false);
+ m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
+ return false;
+ }
+
+private:
+ Vector3i m_Position;
+ cWorldInterface & m_WorldInterface;
+};
+
+
+
+
+
void cBlockBedHandler::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)
{
if (a_WorldInterface.GetDimension() != dimOverworld)
@@ -69,6 +112,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
else
{
+ Vector3i PillowDirection(0, 0, 0);
+
if (Meta & 0x8)
{
// Is pillow
@@ -77,16 +122,30 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
else
{
// Is foot end
- Vector3i Direction = MetaDataToDirection( Meta & 0x7 );
- if (a_ChunkInterface.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
+ VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
+
+ PillowDirection = MetaDataToDirection(Meta & 0x7);
+ if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
{
- a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z);
+ a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
}
}
- a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (Meta | (1 << 2)));
- }
-
- } else {
+
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
+ a_Player->SetIsInBed(true);
+
+ cTimeFastForwardTester Tester;
+ if (a_WorldInterface.ForEachPlayer(Tester))
+ {
+ cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
+ a_WorldInterface.ForEachPlayer(Unsetter);
+ a_WorldInterface.SetTimeOfDay(0);
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0xB); // Where 0xB = 1011, and zero is to make sure 'occupied' bit is always unset
+ }
+ }
+ }
+ else
+ {
a_Player->SendMessageFailure("You can only sleep at night");
}
}
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index caec2b56f..92804aaac 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -4,6 +4,7 @@
#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "WorldInterface.h"
+#include "MetaRotator.h"
#include "../Entities/Player.h"
@@ -11,11 +12,11 @@
class cBlockBedHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h
index ca6850ced..4b2f6f618 100644
--- a/src/Blocks/BlockButton.h
+++ b/src/Blocks/BlockButton.h
@@ -2,16 +2,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
+#include "MetaRotator.h"
class cBlockButtonHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{
public:
cBlockButtonHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{
}
@@ -101,7 +102,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
- return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]);
+ return (a_RelY > 0) && (cBlockInfo::IsSolid(BlockIsOn));
}
} ;
diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h
index 83595d2b9..ed441517d 100644
--- a/src/Blocks/BlockCactus.h
+++ b/src/Blocks/BlockCactus.h
@@ -54,7 +54,7 @@ public:
NIBBLETYPE BlockMeta;
if (
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
- (g_BlockIsSolid[BlockType])
+ cBlockInfo::IsSolid(BlockType)
)
{
return false;
diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h
new file mode 100644
index 000000000..36e133388
--- /dev/null
+++ b/src/Blocks/BlockCake.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockCakeHandler :
+ public cBlockHandler
+{
+public:
+ cBlockCakeHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (!a_Player->Feed(2, 0.1))
+ {
+ return;
+ }
+
+ if (Meta >= 5)
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ else
+ {
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta + 1);
+ }
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // Give nothing
+ }
+
+ virtual bool IsUseable(void) override
+ {
+ return true;
+ }
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.cloth";
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h
index 2e1032d2b..41b79b6c3 100644
--- a/src/Blocks/BlockCauldron.h
+++ b/src/Blocks/BlockCauldron.h
@@ -23,7 +23,7 @@ public:
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
{
- char Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
switch (a_Player->GetEquippedItem().m_ItemType)
{
case E_ITEM_WATER_BUCKET:
diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h
index 02ecc4346..a1ded4c26 100644
--- a/src/Blocks/BlockChest.h
+++ b/src/Blocks/BlockChest.h
@@ -4,17 +4,18 @@
#include "BlockEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
+#include "MetaRotator.h"
class cBlockChestHandler :
- public cBlockEntityHandler
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockChestHandler(BLOCKTYPE a_BlockType)
- : cBlockEntityHandler(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index aba390d9d..4dd05366d 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -3,17 +3,18 @@
#include "BlockHandler.h"
#include "BlockRedstoneRepeater.h"
+#include "MetaRotator.h"
class cBlockComparatorHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
@@ -26,6 +27,13 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h
index ffc2b3f8b..8606cf3f3 100644
--- a/src/Blocks/BlockCrops.h
+++ b/src/Blocks/BlockCrops.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
@@ -21,7 +21,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
{
- MTRand rand;
+ cFastRandom rand;
if (a_Meta == 0x7)
{
@@ -31,18 +31,18 @@ public:
case E_BLOCK_CROPS:
{
a_Pickups.push_back(cItem(E_ITEM_WHEAT, 1, 0));
- a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
+ a_Pickups.push_back(cItem(E_ITEM_SEEDS, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_CARROTS:
{
- a_Pickups.push_back(cItem(E_ITEM_CARROT, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
+ a_Pickups.push_back(cItem(E_ITEM_CARROT, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_POTATOES:
{
- a_Pickups.push_back(cItem(E_ITEM_POTATO, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2
- if (rand.randInt(20) == 0)
+ a_Pickups.push_back(cItem(E_ITEM_POTATO, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
+ if (rand.NextInt(21) == 0)
{
// With a 5% chance, drop a poisonous potato as well
a_Pickups.push_back(cItem(E_ITEM_POISONOUS_POTATO, 1, 0));
diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h
index 2559f4839..bde8e4201 100644
--- a/src/Blocks/BlockDirt.h
+++ b/src/Blocks/BlockDirt.h
@@ -2,8 +2,8 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
#include "BlockSlab.h"
+#include "../FastRandom.h"
@@ -39,7 +39,7 @@ public:
BLOCKTYPE Above;
NIBBLETYPE AboveMeta;
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta);
- if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above] && !(cBlockSlabHandler::IsAnySlabType(Above) && (AboveMeta & 0x8))) || IsBlockWater(Above))
+ if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above) && !(cBlockSlabHandler::IsAnySlabType(Above) && (AboveMeta & 0x8))) || IsBlockWater(Above))
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL);
return;
@@ -47,12 +47,12 @@ public:
}
// Grass spreads to adjacent dirt blocks:
- MTRand rand; // TODO: Replace with cFastRandom
+ cFastRandom rand;
for (int i = 0; i < 2; i++) // Pick two blocks to grow to
{
- int OfsX = rand.randInt(2) - 1; // [-1 .. 1]
- int OfsY = rand.randInt(4) - 3; // [-3 .. 1]
- int OfsZ = rand.randInt(2) - 1; // [-1 .. 1]
+ 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]
BLOCKTYPE DestBlock;
NIBBLETYPE DestMeta;
@@ -80,9 +80,12 @@ public:
BLOCKTYPE AboveDest;
NIBBLETYPE AboveMeta;
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
- if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest] || ((cBlockSlabHandler::IsAnySlabType(AboveDest)) && (AboveMeta & 0x8))) && !IsBlockWater(AboveDest))
+ if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest) || ((cBlockSlabHandler::IsAnySlabType(AboveDest)) && (AboveMeta & 0x8))) && !IsBlockWater(AboveDest))
{
- Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
+ if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread))
+ {
+ Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
+ }
}
} // for i - repeat twice
}
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 2ff5c1c37..479c68153 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -9,7 +9,7 @@
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : super(a_BlockType)
{
}
@@ -55,6 +55,29 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
+void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+{
+ UNUSED(a_ChunkInterface);
+
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (Meta & 8)
+ {
+ // Current block is top of the door
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
+ }
+ else
+ {
+ // Current block is bottom of the door
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
+ }
+}
+
+
+
+
+
void cBlockDoorHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@@ -87,3 +110,87 @@ const char * cBlockDoorHandler::GetStepSound(void)
+
+NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta)
+{
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaRotateCCW(a_Meta);
+ }
+}
+
+
+
+NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta)
+{
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaRotateCW(a_Meta);
+ }
+}
+
+
+
+NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta)
+{
+ // Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data
+ // Return a_Meta if panel is a top panel (0x08 bit is set to 1)
+
+ // Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored
+ // in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
+ // so the function can only see either the hinge position or orientation, but not both, at any given time. The class itself
+ // needs extra datamembers.
+ if (a_Meta & 0x08) return a_Meta;
+
+ // Holds open/closed meta data. 0x0C == 1100.
+ NIBBLETYPE OtherMeta = a_Meta & 0x0C;
+
+ // Mirrors according to a table. 0x03 == 0011.
+ switch (a_Meta & 0x03)
+ {
+ case 0x03: return 0x01 + OtherMeta; // South -> North
+ case 0x01: return 0x03 + OtherMeta; // North -> South
+ }
+
+ // Not Facing North or South; No change.
+ return a_Meta;
+}
+
+
+
+NIBBLETYPE cBlockDoorHandler::MetaMirrorYZ(NIBBLETYPE a_Meta)
+{
+ // Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data
+ // Return a_Meta if panel is a top panel (0x08 bit is set to 1)
+
+ // Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored
+ // in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
+ // so the function can only see either the hinge position or orientation, but not both, at any given time.The class itself
+ // needs extra datamembers.
+
+ if (a_Meta & 0x08) return a_Meta;
+
+ // Holds open/closed meta data. 0x0C == 1100.
+ NIBBLETYPE OtherMeta = a_Meta & 0x0C;
+
+ // Mirrors according to a table. 0x03 == 0011.
+ switch (a_Meta & 0x03)
+ {
+ case 0x00: return 0x02 + OtherMeta; // West -> East
+ case 0x02: return 0x00 + OtherMeta; // East -> West
+ }
+
+ // Not Facing North or South; No change.
+ return a_Meta;
+}
+
+
+
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index ef0dbb787..797fe484c 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -4,20 +4,27 @@
#include "BlockHandler.h"
#include "../Entities/Player.h"
#include "Chunk.h"
+#include "MetaRotator.h"
class cBlockDoorHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{
+ typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
public:
cBlockDoorHandler(BLOCKTYPE 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 void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
virtual const char * GetStepSound(void) override;
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
@@ -139,14 +146,14 @@ public:
static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_X, int a_Y, int a_Z)
{
NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_X, a_Y, a_Z);
-
+
a_ChunkInterface.SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData));
-
+
if (OldMetaData & 8)
{
// Current block is top of the door
BLOCKTYPE BottomBlock = a_ChunkInterface.GetBlock(a_X, a_Y - 1, a_Z);
- NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z);
+ NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z);
if (IsDoor(BottomBlock) && !(BottomMeta & 8))
{
@@ -165,8 +172,6 @@ public:
}
}
}
-
-
} ;
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index 30d347ec9..88b61a418 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -6,17 +6,18 @@
#pragma once
#include "../Piston.h"
+#include "MetaRotator.h"
class cBlockDropSpenserHandler :
- public cBlockEntityHandler
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
- cBlockEntityHandler(a_BlockType)
+ cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@@ -34,6 +35,20 @@ public:
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // Down -> Up
+ case 0x01: return 0x00 + OtherMeta; // Up -> Down
+ }
+ // Not Facing Up or Down; No change.
+ return a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h
index b4b0b995d..67955f8ce 100644
--- a/src/Blocks/BlockEnderchest.h
+++ b/src/Blocks/BlockEnderchest.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockEntity.h"
-
+#include "MetaRotator.h"
class cBlockEnderchestHandler :
- public cBlockEntityHandler
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
- : cBlockEntityHandler(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index fb984f345..e202c6610 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockFenceGateHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
@@ -48,6 +48,12 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual bool IsUseable(void) override
{
return true;
diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h
index a25b87858..c8f158e7e 100644
--- a/src/Blocks/BlockFire.h
+++ b/src/Blocks/BlockFire.h
@@ -17,25 +17,27 @@ public:
}
/// Portal boundary and direction variables
- int XZP, XZM, Dir; // For wont of a better name...
+ // 2014_03_30 _X: What are these used for? Why do we need extra variables?
+ int XZP, XZM;
+ NIBBLETYPE Dir;
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
/*
PORTAL FINDING ALGORITH
=======================
- -Get clicked base block
- -Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
- Uses this value as a reference (the 'ceiling')
- -For both directions (if one fails, try the other), BASE (clicked) block:
- -Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
- -If a border was encountered, go the other direction and repeat above
- -Write borders to XZP and XZM, write direction portal faces to Dir
- -Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
+ - Get clicked base block
+ - Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
+ Uses this value as a reference (the 'ceiling')
+ - For both directions (if one fails, try the other), BASE (clicked) block:
+ - Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
+ - If a border was encountered, go the other direction and repeat above
+ - Write borders to XZP and XZM, write direction portal faces to Dir
+ - Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
*/
a_BlockY--; // Because we want the block below the fire
- FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); // Brought to you by Aperture Science
+ FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface);
}
virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
diff --git a/src/Blocks/BlockFlowerPot.h b/src/Blocks/BlockFlowerPot.h
index 4de85f629..fc75ef638 100644
--- a/src/Blocks/BlockFlowerPot.h
+++ b/src/Blocks/BlockFlowerPot.h
@@ -2,101 +2,24 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockEntity.h"
class cBlockFlowerPotHandler :
- public cBlockHandler
+ public cBlockEntityHandler
{
public:
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cBlockEntityHandler(a_BlockType)
{
}
-
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0));
- if (a_BlockMeta == 0)
- {
- return;
- }
- cItem Plant;
- switch (a_BlockMeta)
- {
- case 1: Plant = cItem(E_BLOCK_RED_ROSE, 1, 0); break;
- case 2: Plant = cItem(E_BLOCK_YELLOW_FLOWER, 1, 0); break;
- case 3: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_APPLE); break;
- case 4: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_CONIFER); break;
- case 5: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_BIRCH); break;
- case 6: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_JUNGLE); break;
- case 7: Plant = cItem(E_BLOCK_RED_MUSHROOM, 1, 0); break;
- case 8: Plant = cItem(E_BLOCK_BROWN_MUSHROOM, 1, 0); break;
- case 9: Plant = cItem(E_BLOCK_CACTUS, 1, 0); break;
- case 10: Plant = cItem(E_BLOCK_DEAD_BUSH, 1, 0); break;
- case 11: Plant = cItem(E_BLOCK_TALL_GRASS, 1, E_META_TALL_GRASS_FERN); break;
- default: return;
- }
- a_Pickups.push_back(Plant);
- }
-
-
- void OnUse(cWorld * a_World, cWorldInterface * a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
- {
- NIBBLETYPE Meta = a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ );
- if (Meta != 0)
- {
- // Already filled
- return;
- }
-
- switch (a_Player->GetEquippedItem().m_ItemType)
- {
- case E_BLOCK_RED_ROSE: Meta = 1; break;
- case E_BLOCK_YELLOW_FLOWER: Meta = 2; break;
- case E_BLOCK_SAPLING:
- {
- switch (a_Player->GetEquippedItem().m_ItemDamage)
- {
- case E_META_SAPLING_APPLE: Meta = 3; break;
- case E_META_SAPLING_CONIFER: Meta = 4; break;
- case E_META_SAPLING_BIRCH: Meta = 5; break;
- case E_META_SAPLING_JUNGLE: Meta = 6; break;
- }
- break;
- }
- case E_BLOCK_RED_MUSHROOM: Meta = 7; break;
- case E_BLOCK_BROWN_MUSHROOM: Meta = 8; break;
- case E_BLOCK_CACTUS: Meta = 9; break;
- case E_BLOCK_DEAD_BUSH: Meta = 10; break;
- case E_BLOCK_TALL_GRASS:
- {
- if (a_Player->GetEquippedItem().m_ItemDamage == E_META_TALL_GRASS_FERN)
- {
- Meta = 11;
- }
- else
- {
- return;
- }
- break;
- }
- }
-
- if (a_Player->GetGameMode() != gmCreative)
- {
- a_Player->GetInventory().RemoveOneEquippedItem();
- }
- a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
- }
-
-
- virtual bool IsUseable(void) override
- {
- return true;
}
} ;
diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h
index 37885e4de..d486d642d 100644
--- a/src/Blocks/BlockFluid.h
+++ b/src/Blocks/BlockFluid.h
@@ -93,6 +93,7 @@ public:
// Check if it's fuel:
BLOCKTYPE BlockType;
if (
+ ((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)
)
@@ -119,6 +120,7 @@ public:
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
{
if (
+ ((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/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index 27ef2689f..a7a807957 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -4,17 +4,17 @@
#include "BlockEntity.h"
#include "../World.h"
#include "../Piston.h"
-
+#include "MetaRotator.h"
class cBlockFurnaceHandler :
- public cBlockEntityHandler
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
- cBlockFurnaceHandler(BLOCKTYPE a_BlockType) :
- cBlockEntityHandler(a_BlockType)
+ cBlockFurnaceHandler(BLOCKTYPE a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 834727c9a..7fd8c183c 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -6,10 +6,12 @@
#include "../Root.h"
#include "../Bindings/PluginManager.h"
#include "../Chunk.h"
+#include "BlockAnvil.h"
#include "BlockBed.h"
#include "BlockBrewingStand.h"
#include "BlockButton.h"
#include "BlockCactus.h"
+#include "BlockCake.h"
#include "BlockCarpet.h"
#include "BlockCauldron.h"
#include "BlockChest.h"
@@ -39,6 +41,7 @@
#include "BlockIce.h"
#include "BlockLadder.h"
#include "BlockLeaves.h"
+#include "BlockLilypad.h"
#include "BlockNewLeaves.h"
#include "BlockLever.h"
#include "BlockMelon.h"
@@ -57,6 +60,7 @@
#include "BlockRedstoneLamp.h"
#include "BlockRedstoneRepeater.h"
#include "BlockRedstoneTorch.h"
+#include "BlockTNT.h"
#include "BlockSand.h"
#include "BlockSapling.h"
#include "BlockSideways.h"
@@ -77,33 +81,6 @@
-bool cBlockHandler::m_HandlerInitialized = false;
-cBlockHandler * cBlockHandler::m_BlockHandler[256];
-
-
-
-
-
-cBlockHandler * cBlockHandler::GetBlockHandler(BLOCKTYPE a_BlockType)
-{
- if (!m_HandlerInitialized)
- {
- // We have to initialize
- memset(m_BlockHandler, 0, sizeof(m_BlockHandler));
- m_HandlerInitialized = true;
- }
- if (m_BlockHandler[a_BlockType] != NULL)
- {
- return m_BlockHandler[a_BlockType];
- }
-
- return m_BlockHandler[a_BlockType] = CreateBlockHandler(a_BlockType);
-}
-
-
-
-
-
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
@@ -111,12 +88,14 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
// Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
+ case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType);
+ case E_BLOCK_CAKE: return new cBlockCakeHandler (a_BlockType);
case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType);
case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType);
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
@@ -164,6 +143,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType);
+ case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType);
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
@@ -172,6 +152,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType);
+ case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType);
case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType);
@@ -192,7 +173,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_REDSTONE_REPEATER_ON: return new cBlockRedstoneRepeaterHandler(a_BlockType);
case E_BLOCK_REDSTONE_TORCH_OFF: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_TORCH_ON: return new cBlockRedstoneTorchHandler (a_BlockType);
- case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
+ case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
case E_BLOCK_RED_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_RED_ROSE: return new cBlockFlowerHandler (a_BlockType);
case E_BLOCK_SAND: return new cBlockSandHandler (a_BlockType);
@@ -212,6 +193,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
+ case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
@@ -231,20 +213,6 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
-void cBlockHandler::Deinit()
-{
- for (int i = 0; i < 256; i++)
- {
- delete m_BlockHandler[i];
- }
- memset(m_BlockHandler, 0, sizeof(m_BlockHandler)); // Don't leave any dangling pointers around, just in case
- m_HandlerInitialized = false;
-}
-
-
-
-
-
cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
{
m_BlockType = a_BlockType;
@@ -329,7 +297,7 @@ void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_Bl
{
if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height))
{
- GetBlockHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
}
}
@@ -361,6 +329,14 @@ void cBlockHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface &
+void cBlockHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+{
+}
+
+
+
+
+
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index a2913d7f8..3a3efb3cc 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -23,6 +23,8 @@ class cBlockHandler
{
public:
cBlockHandler(BLOCKTYPE a_BlockType);
+
+ virtual ~cBlockHandler() {}
/// Called when the block gets ticked either by a random tick or by a queued tick.
/// Note that the coords are chunk-relative!
@@ -69,6 +71,9 @@ public:
/// Called if the user right clicks the block and the block is useable
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);
+ /** Called when a Right Click to this Block is cancelled */
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
+
/// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary>
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
@@ -136,30 +141,14 @@ public:
/// <returns>Block meta following mirroring</returns>
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; }
- /// <summary>Get the blockhandler for a specific block id</summary>
- static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType);
-
- /// <summary>Deletes all initialised block handlers</summary>
- static void Deinit();
-
protected:
BLOCKTYPE m_BlockType;
// Creates a new blockhandler for the given block type. For internal use only, use ::GetBlockHandler() instead.
- static cBlockHandler *CreateBlockHandler(BLOCKTYPE a_BlockType);
- static cBlockHandler *m_BlockHandler[256];
- static bool m_HandlerInitialized; //used to detect if the blockhandlers are initialized
-};
-
+ static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType);
-
-
-
-// Shortcut to get the blockhandler for a specific block
-inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
-{
- return cBlockHandler::GetBlockHandler(a_BlockType);
-}
+ friend class cBlockInfo;
+};
diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h
index 59b84aa0e..a882bb077 100644
--- a/src/Blocks/BlockHopper.h
+++ b/src/Blocks/BlockHopper.h
@@ -3,16 +3,16 @@
// Declares the cBlockHopperHandler class representing the handler for the Hopper block
-
+#include "MetaRotator.h"
class cBlockHopperHandler :
- public cBlockEntityHandler
+ public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockHopperHandler(BLOCKTYPE a_BlockType)
- : cBlockEntityHandler(a_BlockType)
+ : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@@ -39,6 +39,21 @@ public:
}
return true;
}
+
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // Down -> Up
+ case 0x01: return 0x00 + OtherMeta; // Up -> Down
+ }
+ // Not Facing Up or Down; No change.
+ return a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h
index 6a105d5c9..a605edf3f 100644
--- a/src/Blocks/BlockLadder.h
+++ b/src/Blocks/BlockLadder.h
@@ -9,11 +9,11 @@
class cBlockLadderHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockLadderHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@@ -91,7 +91,7 @@ public:
AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
- return g_BlockIsSolid[a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)];
+ return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ));
}
diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h
index 7b8f0b378..8af14686e 100644
--- a/src/Blocks/BlockLeaves.h
+++ b/src/Blocks/BlockLeaves.h
@@ -1,6 +1,6 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
#include "../World.h"
#include "../BlockArea.h"
@@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
+ case E_BLOCK_NEW_LOG: return true; \
}
bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
@@ -36,16 +37,18 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
- MTRand rand;
+ cFastRandom rand;
// Only the first 2 bits contain the display information, the others are for growing
- if (rand.randInt(5) == 0)
+ if (rand.NextInt(6) == 0)
{
a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 3));
}
- if ((a_BlockMeta & 3) == E_META_SAPLING_APPLE)
+
+ // 1 % chance of dropping an apple, if the leaves' type is Apple Leaves
+ if ((a_BlockMeta & 3) == E_META_LEAVES_APPLE)
{
- if (rand.rand(100) == 0)
+ if (rand.NextInt(101) == 0)
{
a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
}
@@ -57,11 +60,10 @@ public:
{
cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ);
- //0.5% chance of dropping an apple
+ // 0.5% chance of dropping an apple, if the leaves' type is Apple Leaves:
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- //check if Oak (0x1 and 0x2 bit not set)
- MTRand rand;
- if(!(Meta & 3) && rand.randInt(200) == 100)
+ cFastRandom rand;
+ if (((Meta & 3) == E_META_LEAVES_APPLE) && (rand.NextInt(201) == 100))
{
cItems Drops;
Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h
index 48c7e774b..ad2ae29e5 100644
--- a/src/Blocks/BlockLever.h
+++ b/src/Blocks/BlockLever.h
@@ -1,17 +1,18 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockLeverHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>
{
+ typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> super;
public:
cBlockLeverHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>(a_BlockType)
{
}
@@ -102,7 +103,37 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
- return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]);
+ return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn);
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ switch (a_Meta)
+ {
+ case 0x00: return 0x07; // Ceiling rotation
+ case 0x07: return 0x00;
+
+ case 0x05: return 0x06; // Ground rotation
+ case 0x06: return 0x05;
+
+ default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
+ }
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ switch (a_Meta)
+ {
+ case 0x00: return 0x07; // Ceiling rotation
+ case 0x07: return 0x00;
+
+ case 0x05: return 0x06; // Ground rotation
+ case 0x06: return 0x05;
+
+ default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
+ }
}
} ;
diff --git a/src/Blocks/BlockLilypad.h b/src/Blocks/BlockLilypad.h
new file mode 100644
index 000000000..2dd4ec768
--- /dev/null
+++ b/src/Blocks/BlockLilypad.h
@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "Entities/Pickup.h"
+
+
+
+
+class cBlockLilypadHandler :
+ public cBlockHandler
+{
+public:
+ cBlockLilypadHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // Reset meta to zero
+ a_Pickups.push_back(cItem(E_BLOCK_LILY_PAD, 1, 0));
+ }
+};
+
+
+
+
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index 6a00c3acd..acd1c88fb 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -21,6 +21,103 @@ public:
{
a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
}
+
+ bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
+ {
+ if (a_BlockY < 2)
+ {
+ return false;
+ }
+
+ class cCallback : public cMobHeadCallback
+ {
+ bool m_IsWither;
+
+ virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
+ {
+ m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
+
+ return false;
+ }
+
+ public:
+ cCallback () : m_IsWither(false) {}
+
+ bool IsWither(void) const { return m_IsWither; }
+
+ void Reset(void) { m_IsWither = false; }
+ } CallbackA, CallbackB;
+
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
+
+ if (!CallbackA.IsWither())
+ {
+ return false;
+ }
+
+ CallbackA.Reset();
+
+ BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+ BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
+
+ if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND))
+ {
+ return false;
+ }
+
+ a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
+ a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
+
+ BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ);
+ BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ);
+
+ if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Block entities
+ a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Spawn the wither:
+ a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+
+ return true;
+ }
+
+ CallbackA.Reset();
+ CallbackB.Reset();
+
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
+ a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
+
+ Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1);
+ Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1);
+
+ if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
+
+ // Block entities
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
+
+ // Spawn the wither:
+ a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+
+ return true;
+ }
+
+ return false;
+ }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
@@ -29,7 +126,7 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
- class cCallback : public cMobHeadBlockCallback
+ class cCallback : public cMobHeadCallback
{
cPlayer * m_Player;
NIBBLETYPE m_OldBlockMeta;
@@ -45,22 +142,42 @@ public:
a_MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
a_MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
+ a_MobHeadEntity->GetWorld()->BroadcastBlockEntity(a_MobHeadEntity->GetPosX(), a_MobHeadEntity->GetPosY(), a_MobHeadEntity->GetPosZ(), m_Player->GetClientHandle());
return false;
}
public:
- cCallback (cPlayer * a_Player, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
- m_Player(a_Player),
+ cCallback (cPlayer * a_CBPlayer, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
+ m_Player(a_CBPlayer),
m_OldBlockMeta(a_OldBlockMeta),
m_NewBlockMeta(a_NewBlockMeta)
{}
};
cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace));
- a_BlockMeta = a_BlockFace;
+ a_BlockMeta = (NIBBLETYPE)a_BlockFace;
cWorld * World = (cWorld *) &a_WorldInterface;
- World->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
+ World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
+
+ if (a_BlockMeta == SKULL_TYPE_WITHER)
+ {
+ static const Vector3i Coords[] =
+ {
+ Vector3i( 0, 0, 0),
+ Vector3i( 1, 0, 0),
+ Vector3i(-1, 0, 0),
+ Vector3i( 0, 0, 1),
+ Vector3i( 0, 0, -1),
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i)
+ {
+ if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
+ {
+ break;
+ }
+ } // for i - Coords[]
+ }
}
} ;
diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h
index 623cfda64..135d418d7 100644
--- a/src/Blocks/BlockMushroom.h
+++ b/src/Blocks/BlockMushroom.h
@@ -17,6 +17,9 @@ public:
}
+ // TODO: Add Mushroom Spread
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
@@ -39,6 +42,7 @@ public:
case E_BLOCK_CACTUS:
case E_BLOCK_ICE:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
case E_BLOCK_AIR:
{
return false;
diff --git a/src/Blocks/BlockMycelium.h b/src/Blocks/BlockMycelium.h
index 7f897c72a..2a8ef5fca 100644
--- a/src/Blocks/BlockMycelium.h
+++ b/src/Blocks/BlockMycelium.h
@@ -16,6 +16,8 @@ public:
{
}
+ // TODO: Add Mycel Spread
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0));
diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h
index 923180e19..812cf906f 100644
--- a/src/Blocks/BlockNetherWart.h
+++ b/src/Blocks/BlockNetherWart.h
@@ -2,14 +2,13 @@
#pragma once
#include "BlockHandler.h"
-#include "../MersenneTwister.h"
+#include "../FastRandom.h"
#include "../World.h"
-/// Common class that takes care of carrots, potatoes and wheat
class cBlockNetherWartHandler :
public cBlockHandler
{
@@ -22,12 +21,12 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
{
- MTRand rand;
+ cFastRandom rand;
if (a_Meta == 0x7)
{
- // Is fully grown, drop the entire produce:
- a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0));
+ // Fully grown, drop the entire produce:
+ a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, (char)(1 + (rand.NextInt(3) + rand.NextInt(3))) / 2, 0));
}
else
{
@@ -35,18 +34,20 @@ public:
}
}
+
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
- NIBBLETYPE Meta = a_Chunk.GetMeta (a_RelX, a_RelY, a_RelZ);
-
+ NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
if (Meta < 7)
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta);
}
}
+
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
+ // Needs to be placed on top of a Soulsand block:
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND));
}
} ;
diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h
index 7428c9a7a..3a36c40b1 100644
--- a/src/Blocks/BlockPluginInterface.h
+++ b/src/Blocks/BlockPluginInterface.h
@@ -1,8 +1,14 @@
#pragma once
+/** This interface is used to decouple block handlers from the cPluginManager dependancy through cWorld.
+The block handlers call this interface, which is then implemented by the specific classes that
+the caller provides.
+*/
class cBlockPluginInterface
{
public:
+ virtual ~cBlockPluginInterface() {}
+
virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
};
diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h
index 349f52605..ac2b9817a 100644
--- a/src/Blocks/BlockPumpkin.h
+++ b/src/Blocks/BlockPumpkin.h
@@ -1,16 +1,16 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockPumpkinHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false>
{
public:
cBlockPumpkinHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h
index 52d6f60b3..ad78d290a 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -98,7 +98,7 @@ public:
{
return false;
}
- if (!g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)])
+ if (!cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
{
return false;
}
@@ -130,7 +130,7 @@ public:
// Too close to the edge, cannot simulate
return true;
}
- return g_BlockIsSolid[BlockType];
+ return cBlockInfo::IsSolid(BlockType);
}
}
return true;
@@ -431,9 +431,145 @@ public:
}
break;
}
+ default: break;
}
return true;
}
+
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag when a_Meta is in the range 0x00--0x05 and 0x0A--0x0F.
+ // Bit 0x08 specifies direction when a_Meta is in the range 0x06-0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Rotates according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // North/South -> East/West
+ case 0x01: return 0x00 + OtherMeta; // East/West -> North/South
+
+ case 0x02: return 0x04 + OtherMeta; // Asc. East -> Asc. North
+ case 0x04: return 0x03 + OtherMeta; // Asc. North -> Asc. West
+ case 0x03: return 0x05 + OtherMeta; // Asc. West -> Asc. South
+ case 0x05: return 0x02 + OtherMeta; // Asc. South -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr.
+ case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr.
+ case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr.
+ case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Rotates according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // North/South -> East/West
+ case 0x01: return 0x00 + OtherMeta; // East/West -> North/South
+
+ case 0x02: return 0x05 + OtherMeta; // Asc. East -> Asc. South
+ case 0x05: return 0x03 + OtherMeta; // Asc. South -> Asc. West
+ case 0x03: return 0x04 + OtherMeta; // Asc. West -> Asc. North
+ case 0x04: return 0x02 + OtherMeta; // Asc. North -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr.
+ case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr.
+ case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr.
+ case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x05: return 0x04 + OtherMeta; // Asc. South -> Asc. North
+ case 0x04: return 0x05 + OtherMeta; // Asc. North -> Asc. South
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr.
+ case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr.
+ case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr.
+ case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09.
+ if ((a_Meta < 0x06) || (a_Meta > 0x09))
+ {
+ // Save powered rail flag.
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors according to table; 0x07 == 0111.
+ // Rails can either be flat (North/South) or Ascending (Asc. East)
+ switch (a_Meta & 0x07)
+ {
+ case 0x02: return 0x03 + OtherMeta; // Asc. East -> Asc. West
+ case 0x03: return 0x02 + OtherMeta; // Asc. West -> Asc. East
+ }
+ }
+ else
+ {
+ switch (a_Meta)
+ {
+ // Corner Directions
+ case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr.
+ case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr.
+ case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr.
+ case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr.
+ }
+ }
+ // To avoid a compiler warning;
+ return a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h
index 10de96197..a898c9acb 100644
--- a/src/Blocks/BlockRedstone.h
+++ b/src/Blocks/BlockRedstone.h
@@ -20,7 +20,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) && g_BlockFullyOccupiesVoxel[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]);
+ return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
}
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index eb0918acf..fe6cd21b9 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -3,17 +3,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
-
+#include "MetaRotator.h"
class cBlockRedstoneRepeaterHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
@@ -29,7 +29,7 @@ public:
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
-
+
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
{
@@ -37,6 +37,13 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h
index 69c0a7230..d67c3aa24 100644
--- a/src/Blocks/BlockSideways.h
+++ b/src/Blocks/BlockSideways.h
@@ -29,7 +29,13 @@ public:
return true;
}
-
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3);
+ }
+
+
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_WoodMeta)
{
switch (a_BlockFace)
diff --git a/src/Blocks/BlockSign.h b/src/Blocks/BlockSign.h
index cd0c02a40..6c0becfd6 100644
--- a/src/Blocks/BlockSign.h
+++ b/src/Blocks/BlockSign.h
@@ -71,6 +71,37 @@ public:
{
a_Player->GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
}
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ return (++a_Meta) & 0x0F;
+ }
+
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ return (--a_Meta) & 0x0F;
+ }
+
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
+ {
+ // Mirrors signs over the XY plane (North-South Mirroring)
+
+ // There are 16 meta values which correspond to different directions.
+ // These values are equated to angles on a circle; 0x08 = 180 degrees.
+ return (a_Meta < 0x08) ? 0x08 + a_Meta : 0x08 - a_Meta;
+ }
+
+
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
+ {
+ // Mirrors signs over the YZ plane (East-West Mirroring)
+
+ // There are 16 meta values which correspond to different directions.
+ // These values are equated to angles on a circle; 0x10 = 360 degrees.
+ return 0x10 - a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h
index 7cd2c97b2..76f5ed0e7 100644
--- a/src/Blocks/BlockSlab.h
+++ b/src/Blocks/BlockSlab.h
@@ -11,8 +11,7 @@
#include "BlockHandler.h"
#include "../Items/ItemHandler.h"
-
-
+#include "Root.h"
@@ -40,41 +39,9 @@ public:
) override
{
a_BlockType = m_BlockType;
- BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE Meta = (NIBBLETYPE) a_Player->GetEquippedItem().m_ItemDamage;
- // HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type));
-
- // Check if the block at the coordinates is a slab. Eligibility for combining has already been processed in ClientHandle
- if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
- {
- // Call the function in ClientHandle that places a block when the client sends the packet,
- // so that plugins may interfere with the placement.
-
- if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM))
- {
- // Top and bottom faces need no parameter modification
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- else
- {
- // The other faces need to distinguish between top and bottom cursor positions
- if (a_CursorY > 7)
- {
- // Edit the call to use BLOCK_FACE_BOTTOM, otherwise it places incorrectly
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_TOP, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- else
- {
- // Edit the call to use BLOCK_FACE_TOP, otherwise it places incorrectly
- a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_BOTTOM, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
- }
- }
- return false; // Cancel the event, because dblslabs were already placed, nothing else needed
- }
-
- // Place the single-slab with correct metas:
+ // Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet)
switch (a_BlockFace)
{
case BLOCK_FACE_TOP:
@@ -105,7 +72,16 @@ public:
a_BlockMeta = Meta & 0x7; break;
}
}
+ case BLOCK_FACE_NONE: return false;
} // switch (a_BlockFace)
+
+ // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle
+ // Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time
+ if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ a_BlockType = GetDoubleSlabType(m_BlockType);
+ }
+
return true;
}
@@ -184,6 +160,15 @@ public:
ASSERT(!"Unhandled double slab type!");
return "";
}
+
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ NIBBLETYPE OtherMeta = a_Meta & 0x07; // Contains unrelated meta data.
+
+ // 8th bit is up/down. 1 right-side-up, 0 is up-side-down.
+ return (a_Meta & 0x08) ? 0x00 + OtherMeta : 0x01 + OtherMeta;
+ }
} ;
diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h
index a3daf0393..b21995d3c 100644
--- a/src/Blocks/BlockSnow.h
+++ b/src/Blocks/BlockSnow.h
@@ -72,7 +72,7 @@ public:
BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ);
- if (g_BlockIsSnowable[BlockBelow] || ((BlockBelow == E_BLOCK_SNOW) && (MetaBelow == 7)))
+ if (cBlockInfo::IsSnowable(BlockBelow) || ((BlockBelow == E_BLOCK_SNOW) && (MetaBelow == 7)))
{
// If block below is snowable, or it is a thin slow block and has a meta of 7 (full thin snow block), say yay
return true;
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index c1887bc46..09ff254a6 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockStairsHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
{
public:
cBlockStairsHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
{
}
@@ -25,6 +25,12 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorZ);
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
@@ -43,10 +49,12 @@ public:
}
break;
}
+ case BLOCK_FACE_NONE: return false;
}
return true;
}
+
virtual const char * GetStepSound(void) override
{
if (
@@ -96,54 +104,6 @@ public:
}
- virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x03; // East -> North
- case 0x01: return TopBits | 0x02; // West -> South
- case 0x02: return TopBits | 0x00; // South -> East
- case 0x03: return TopBits | 0x01; // North -> West
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
- virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x02; // East -> South
- case 0x01: return TopBits | 0x03; // West -> North
- case 0x02: return TopBits | 0x01; // South -> West
- case 0x03: return TopBits | 0x00; // North -> East
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
- virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x00; // East -> East
- case 0x01: return TopBits | 0x01; // West -> West
- case 0x02: return TopBits | 0x03; // South -> North
- case 0x03: return TopBits | 0x02; // North -> South
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Toggle bit 3:
@@ -151,20 +111,6 @@ public:
}
- virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x01; // East -> West
- case 0x01: return TopBits | 0x00; // West -> East
- case 0x02: return TopBits | 0x02; // South -> South
- case 0x03: return TopBits | 0x03; // North -> North
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
} ;
diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h
index 705436345..b726a0901 100644
--- a/src/Blocks/BlockStems.h
+++ b/src/Blocks/BlockStems.h
@@ -17,9 +17,10 @@ public:
{
}
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
- int ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
+ short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
a_Pickups.push_back(cItem(ItemType, 1, 0));
}
diff --git a/src/Blocks/BlockTNT.h b/src/Blocks/BlockTNT.h
new file mode 100644
index 000000000..283a03730
--- /dev/null
+++ b/src/Blocks/BlockTNT.h
@@ -0,0 +1,32 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockTNTHandler :
+ public cBlockHandler
+{
+public:
+ cBlockTNTHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.grass";
+ }
+
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+};
+
+
+
+
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index f2a4c8665..8ddec8de1 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -2,17 +2,17 @@
#include "BlockHandler.h"
#include "../Chunk.h"
-
+#include "MetaRotator.h"
class cBlockTorchHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
{
public:
cBlockTorchHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
{
}
@@ -99,7 +99,7 @@ public:
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace)
{
- if ( !g_BlockFullyOccupiesVoxel[a_BlockType] )
+ if ( !cBlockInfo::FullyOccupiesVoxel(a_BlockType) )
{
return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
}
@@ -129,7 +129,7 @@ public:
{
return Face;
}
- else if ((g_BlockFullyOccupiesVoxel[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM))
+ else if (cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) && (i != BLOCK_FACE_BOTTOM))
{
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
return Face;
@@ -163,7 +163,7 @@ public:
// No need to check for upright orientation, it was done when the torch was placed
return true;
}
- else if ( !g_BlockFullyOccupiesVoxel[BlockInQuestion] )
+ else if ( !cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) )
{
return false;
}
@@ -185,67 +185,6 @@ public:
{
return "step.wood";
}
-
-
- virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x04; // East -> North
- case 0x02: return TopBits | 0x03; // West -> South
- case 0x03: return TopBits | 0x01; // South -> East
- case 0x04: return TopBits | 0x02; // North -> West
- default: return a_Meta; // Floor -> Floor
- }
- }
-
-
- virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x03; // East -> South
- case 0x02: return TopBits | 0x04; // West -> North
- case 0x03: return TopBits | 0x02; // South -> West
- case 0x04: return TopBits | 0x01; // North -> East
- default: return a_Meta; // Floor -> Floor
- }
- }
-
-
- virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x03: return TopBits | 0x04; // South -> North
- case 0x04: return TopBits | 0x03; // North -> South
- default: return a_Meta; // Keep the rest
- }
- }
-
-
- // Mirroring around the XZ plane doesn't make sense for floor torches,
- // the others stay the same, so let's keep all the metas the same.
- // The base class does tht for us, no need to override MetaMirrorXZ()
-
-
- virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x02; // East -> West
- case 0x02: return TopBits | 0x01; // West -> East
- default: return a_Meta; // Keep the rest
- }
- }
} ;
diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h
index 251044afd..6a36ab874 100644
--- a/src/Blocks/BlockTrapdoor.h
+++ b/src/Blocks/BlockTrapdoor.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
class cBlockTrapdoorHandler :
- public cBlockHandler
+ public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>
{
public:
cBlockTrapdoorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>(a_BlockType)
{
}
@@ -42,6 +42,12 @@ public:
World->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@@ -99,7 +105,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
- return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]);
+ return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn);
}
};
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index ee7dcee8a..7bb9dc484 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -1,8 +1,7 @@
-
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotator.h"
@@ -24,6 +23,10 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_Player);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
// TODO: Disallow placement where the vine doesn't attach to something properly
BLOCKTYPE BlockType = 0;
NIBBLETYPE BlockMeta;
@@ -70,7 +73,7 @@ public:
/// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{
- return (a_BlockType == E_BLOCK_LEAVES) || g_BlockIsSolid[a_BlockType];
+ return (a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
}
@@ -80,7 +83,7 @@ public:
static const struct
{
int x, z;
- int Bit;
+ NIBBLETYPE Bit;
} Coords[] =
{
{ 0, 1, 1}, // south, ZP
@@ -88,7 +91,7 @@ public:
{ 0, -1, 4}, // north, ZM
{ 1, 0, 8}, // east, XP
} ;
- int res = 0;
+ NIBBLETYPE res = 0;
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
{
BLOCKTYPE BlockType;
@@ -162,11 +165,20 @@ public:
return false;
}
- virtual void OnUpdate(cWorld * a_World, int X, int Y, int Z)
+ virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
- if (a_World->GetBlock(X, Y - 1, Z) == E_BLOCK_AIR)
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_WorldInterface);
+ UNUSED(a_BlockPluginInterface);
+
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
+ if (Block == E_BLOCK_AIR)
{
- a_World->SetBlock(X, Y - 1, Z, E_BLOCK_VINES, a_World->GetBlockMeta(X, Y, Z));
+ if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX * cChunkDef::Width, a_RelY - 1, a_RelZ * cChunkDef::Width, ssVineSpread))
+ {
+ a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ }
}
}
@@ -180,20 +192,21 @@ public:
{
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
}
-
-
+
+
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bits 2 and 4 stay, bits 1 and 3 swap
- return ((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
+ return (NIBBLETYPE)((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
}
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
// Bits 1 and 3 stay, bits 2 and 4 swap
- return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
+ return (NIBBLETYPE)((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
}
+
} ;
diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h
index f6ccd580b..b1b450690 100644
--- a/src/Blocks/BroadcastInterface.h
+++ b/src/Blocks/BroadcastInterface.h
@@ -4,7 +4,9 @@
class cBroadcastInterface
{
public:
-
- virtual void BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
- virtual void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
+ virtual ~cBroadcastInterface() {}
+
+ virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
+ virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
+ virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
};
diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp
index b2dda19f4..540581ae7 100644
--- a/src/Blocks/ChunkInterface.cpp
+++ b/src/Blocks/ChunkInterface.cpp
@@ -6,7 +6,7 @@
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z)
{
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z));
+ cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z));
Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
}
diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h
index b30eff1e4..be7c2e0e5 100644
--- a/src/Blocks/ChunkInterface.h
+++ b/src/Blocks/ChunkInterface.h
@@ -5,31 +5,35 @@
#include "../ForEachChunkProvider.h"
#include "WorldInterface.h"
-class cBlockHandler;
-class cChunkInterface : public cForEachChunkProvider
+
+
+
+class cChunkInterface:
+ public cForEachChunkProvider
{
public:
cChunkInterface(cChunkMap * a_ChunkMap) : m_ChunkMap(a_ChunkMap) {}
- BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ)
+ BLOCKTYPE GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return m_ChunkMap->GetBlock(a_BlockX,a_BlockY,a_BlockZ);
}
- BLOCKTYPE GetBlock (const Vector3i & a_Pos )
+ BLOCKTYPE GetBlock(const Vector3i & a_Pos)
{
- return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z );
+ return GetBlock(a_Pos.x, a_Pos.y, a_Pos.z);
}
- NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ)
+ NIBBLETYPE GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return m_ChunkMap->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
}
- bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
+ bool GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{
return m_ChunkMap->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
+
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
@@ -37,7 +41,8 @@ public:
{
m_ChunkMap->SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
- void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
+
+ void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
{
m_ChunkMap->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_MetaData);
}
@@ -55,7 +60,11 @@ public:
{
m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
- void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
+
+ void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta )
+ {
+ FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta );
+ }
void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
@@ -77,3 +86,7 @@ public:
private:
cChunkMap * m_ChunkMap;
};
+
+
+
+
diff --git a/src/Blocks/MetaRotator.h b/src/Blocks/MetaRotator.h
new file mode 100644
index 000000000..899c583e1
--- /dev/null
+++ b/src/Blocks/MetaRotator.h
@@ -0,0 +1,120 @@
+// MetaRotator.h
+
+// Provides a mixin for rotations and reflections
+
+#pragma once
+
+// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
+#ifdef _MSC_VER
+ #pragma warning(disable: 4127) // Conditional expression is constant
+#endif
+
+
+
+
+
+/*
+Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case.
+
+Usage:
+Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state.
+*/
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
+class cMetaRotator : public Base
+{
+public:
+
+ cMetaRotator(BLOCKTYPE a_BlockType) :
+ Base(a_BlockType)
+ {}
+
+ virtual ~cMetaRotator() {}
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
+};
+
+
+
+
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return West | OtherMeta;
+ case West: return North | OtherMeta;
+ case North: return East | OtherMeta;
+ case East: return South | OtherMeta;
+ }
+ if (AssertIfNotMatched)
+ {
+ ASSERT(!"Invalid Meta value");
+ }
+ return a_Meta;
+}
+
+
+
+
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return East | OtherMeta;
+ case East: return North | OtherMeta;
+ case North: return West | OtherMeta;
+ case West: return South | OtherMeta;
+ }
+ if (AssertIfNotMatched)
+ {
+ ASSERT(!"Invalid Meta value");
+ }
+ return a_Meta;
+}
+
+
+
+
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return North | OtherMeta;
+ case North: return South | OtherMeta;
+ }
+ // Not Facing North or South; No change.
+ return a_Meta;
+}
+
+
+
+
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
+NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case West: return East | OtherMeta;
+ case East: return West | OtherMeta;
+ }
+ // Not Facing East or West; No change.
+ return a_Meta;
+}
+
+
+
+
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index b6f2f55a7..bfbb053d9 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -9,7 +9,8 @@ class cItems;
class cWorldInterface
{
public:
-
+ virtual ~cWorldInterface() {}
+
virtual Int64 GetTimeOfDay(void) const = 0;
virtual Int64 GetWorldAge(void) const = 0;
@@ -27,4 +28,13 @@ public:
/** 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, cMonster::eType a_MonsterType) = 0;
+
+ /** Sends the block on those coords to the player */
+ virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
+
+ /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
+ virtual bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback) = 0;
+
+ virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0;
+
};
diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp
index aab51c539..482f9923f 100644
--- a/src/BoundingBox.cpp
+++ b/src/BoundingBox.cpp
@@ -10,7 +10,7 @@
-#if SELF_TEST
+#ifdef SELF_TEST
/** A simple self-test that is executed on program start, used to verify bbox functionality */
static class SelfTest_BoundingBox
diff --git a/src/BoundingBox.h b/src/BoundingBox.h
index 9ac5f11b8..a7c6c3eea 100644
--- a/src/BoundingBox.h
+++ b/src/BoundingBox.h
@@ -8,7 +8,7 @@
#pragma once
-#include "Vector3d.h"
+#include "Vector3.h"
#include "Defines.h"
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index d2d3beb97..1893d89a8 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -44,10 +44,10 @@
-#if 0
+#ifdef SELF_TEST
/// Self-test of the VarInt-reading and writing code
-class cByteBufferSelfTest
+static class cByteBufferSelfTest
{
public:
cByteBufferSelfTest(void)
@@ -62,11 +62,11 @@ public:
cByteBuffer buf(50);
buf.Write("\x05\xac\x02\x00", 4);
UInt32 v1;
- assert(buf.ReadVarInt(v1) && (v1 == 5));
+ assert_test(buf.ReadVarInt(v1) && (v1 == 5));
UInt32 v2;
- assert(buf.ReadVarInt(v2) && (v2 == 300));
+ assert_test(buf.ReadVarInt(v2) && (v2 == 300));
UInt32 v3;
- assert(buf.ReadVarInt(v3) && (v3 == 0));
+ assert_test(buf.ReadVarInt(v3) && (v3 == 0));
}
void TestWrite(void)
@@ -77,8 +77,8 @@ public:
buf.WriteVarInt(0);
AString All;
buf.ReadAll(All);
- assert(All.size() == 4);
- assert(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
+ assert_test(All.size() == 4);
+ assert_test(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
}
void TestWrap(void)
@@ -86,18 +86,18 @@ public:
cByteBuffer buf(3);
for (int i = 0; i < 1000; i++)
{
- int FreeSpace = buf.GetFreeSpace();
- assert(buf.GetReadableSpace() == 0);
- assert(FreeSpace > 0);
- assert(buf.Write("a", 1));
- assert(buf.CanReadBytes(1));
- assert(buf.GetReadableSpace() == 1);
+ size_t FreeSpace = buf.GetFreeSpace();
+ assert_test(buf.GetReadableSpace() == 0);
+ assert_test(FreeSpace > 0);
+ assert_test(buf.Write("a", 1));
+ assert_test(buf.CanReadBytes(1));
+ assert_test(buf.GetReadableSpace() == 1);
unsigned char v = 0;
- assert(buf.ReadByte(v));
- assert(v == 'a');
- assert(buf.GetReadableSpace() == 0);
+ assert_test(buf.ReadByte(v));
+ assert_test(v == 'a');
+ assert_test(buf.GetReadableSpace() == 0);
buf.CommitRead();
- assert(buf.GetFreeSpace() == FreeSpace); // We're back to normal
+ assert_test(buf.GetFreeSpace() == FreeSpace); // We're back to normal
}
}
@@ -171,21 +171,22 @@ cByteBuffer::~cByteBuffer()
-bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
+bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
// Store the current free space for a check after writing:
- int CurFreeSpace = GetFreeSpace();
- int CurReadableSpace = GetReadableSpace();
- int WrittenBytes = 0;
+ size_t CurFreeSpace = GetFreeSpace();
+ size_t CurReadableSpace = GetReadableSpace();
+ size_t WrittenBytes = 0;
if (CurFreeSpace < a_Count)
{
return false;
}
- int TillEnd = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_WritePos);
+ size_t TillEnd = m_BufferSize - m_WritePos;
if (TillEnd <= a_Count)
{
// Need to wrap around the ringbuffer end
@@ -216,16 +217,20 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
-int cByteBuffer::GetFreeSpace(void) const
+size_t cByteBuffer::GetFreeSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_WritePos >= m_DataStart)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT((m_BufferSize - m_WritePos + m_DataStart) >= 1);
return m_BufferSize - m_WritePos + m_DataStart - 1;
}
// Single free space partition:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT(m_BufferSize - m_WritePos >= 1);
return m_DataStart - m_WritePos - 1;
}
@@ -234,10 +239,12 @@ int cByteBuffer::GetFreeSpace(void) const
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
-int cByteBuffer::GetUsedSpace(void) const
+size_t cByteBuffer::GetUsedSpace(void) const
{
CHECK_THREAD;
CheckValid();
+ ASSERT(m_BufferSize >= GetFreeSpace());
+ ASSERT((m_BufferSize - GetFreeSpace()) >= 1);
return m_BufferSize - GetFreeSpace() - 1;
}
@@ -246,16 +253,18 @@ int cByteBuffer::GetUsedSpace(void) const
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
-int cByteBuffer::GetReadableSpace(void) const
+size_t cByteBuffer::GetReadableSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_ReadPos > m_WritePos)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_ReadPos);
return m_BufferSize - m_ReadPos + m_WritePos;
}
// Single readable space partition:
+ ASSERT(m_WritePos >= m_ReadPos);
return m_WritePos - m_ReadPos ;
}
@@ -263,7 +272,7 @@ int cByteBuffer::GetReadableSpace(void) const
-bool cByteBuffer::CanReadBytes(int a_Count) const
+bool cByteBuffer::CanReadBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -274,7 +283,7 @@ bool cByteBuffer::CanReadBytes(int a_Count) const
-bool cByteBuffer::CanWriteBytes(int a_Count) const
+bool cByteBuffer::CanWriteBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -450,7 +459,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
}
if (Size > MAX_STRING_SIZE)
{
- LOGWARNING("%s: String too large: %llu (%llu KiB)", __FUNCTION__, Size, Size / 1024);
+ LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
}
return ReadString(a_Value, (int)Size);
}
@@ -650,15 +659,14 @@ bool cByteBuffer::WriteLEInt(int a_Value)
-bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
+bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
char * Dst = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -684,14 +692,14 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
-bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
+bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
PUTBYTES(a_Count);
char * Src = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_WritePos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -714,22 +722,22 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
-bool cByteBuffer::ReadString(AString & a_String, int a_Count)
+bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
a_String.clear();
a_String.reserve(a_Count);
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
if (BytesToEndOfBuffer > 0)
{
a_String.assign(m_Buffer + m_ReadPos, BytesToEndOfBuffer);
+ ASSERT(a_Count >= BytesToEndOfBuffer);
a_Count -= BytesToEndOfBuffer;
}
m_ReadPos = 0;
@@ -759,7 +767,7 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
{
return false;
}
- RawBEToUTF8((short *)(RawData.data()), a_NumChars, a_String);
+ RawBEToUTF8(RawData.data(), a_NumChars, a_String);
return true;
}
@@ -767,11 +775,10 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
-bool cByteBuffer::SkipRead(int a_Count)
+bool cByteBuffer::SkipRead(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
if (!CanReadBytes(a_Count))
{
return false;
@@ -809,6 +816,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
size_t num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes;
VERIFY(ReadBuf(buf, num));
VERIFY(a_Dst.Write(buf, num));
+ ASSERT(a_NumBytes >= num);
a_NumBytes -= num;
}
return true;
@@ -846,13 +854,15 @@ void cByteBuffer::ReadAgain(AString & a_Out)
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
CHECK_THREAD;
CheckValid();
- int DataStart = m_DataStart;
+ size_t DataStart = m_DataStart;
if (m_ReadPos < m_DataStart)
{
// Across the ringbuffer end, read the first part and adjust next part's start:
+ ASSERT(m_BufferSize >= m_DataStart);
a_Out.append(m_Buffer + m_DataStart, m_BufferSize - m_DataStart);
DataStart = 0;
}
+ ASSERT(m_ReadPos >= DataStart);
a_Out.append(m_Buffer + DataStart, m_ReadPos - DataStart);
}
@@ -860,7 +870,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
-void cByteBuffer::AdvanceReadPos(int a_Count)
+void cByteBuffer::AdvanceReadPos(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index cbce119b1..1915467f3 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -31,25 +31,25 @@ public:
~cByteBuffer();
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
- bool Write(const char * a_Bytes, int a_Count);
+ bool Write(const char * a_Bytes, size_t a_Count);
/// Returns the number of bytes that can be successfully written to the ringbuffer
- int GetFreeSpace(void) const;
+ size_t GetFreeSpace(void) const;
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
- int GetUsedSpace(void) const;
+ size_t GetUsedSpace(void) const;
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
- int GetReadableSpace(void) const;
+ size_t GetReadableSpace(void) const;
/// Returns the current data start index. For debugging purposes.
- int GetDataStart(void) const { return m_DataStart; }
+ size_t GetDataStart(void) const { return m_DataStart; }
/// Returns true if the specified amount of bytes are available for reading
- bool CanReadBytes(int a_Count) const;
+ bool CanReadBytes(size_t a_Count) const;
/// Returns true if the specified amount of bytes are available for writing
- bool CanWriteBytes(int a_Count) const;
+ 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);
@@ -92,19 +92,19 @@ public:
bool WriteLEInt (int a_Value);
/// Reads a_Count bytes into a_Buffer; returns true if successful
- bool ReadBuf(void * a_Buffer, int a_Count);
+ bool ReadBuf(void * a_Buffer, size_t a_Count);
/// Writes a_Count bytes into a_Buffer; returns true if successful
- bool WriteBuf(const void * a_Buffer, int a_Count);
+ bool WriteBuf(const void * a_Buffer, size_t a_Count);
/// Reads a_Count bytes into a_String; returns true if successful
- bool ReadString(AString & a_String, int a_Count);
+ bool ReadString(AString & a_String, size_t a_Count);
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
bool ReadUTF16String(AString & a_String, int a_NumChars);
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
- bool SkipRead(int a_Count);
+ bool SkipRead(size_t a_Count);
/// Reads all available data into a_Data
void ReadAll(AString & a_Data);
@@ -126,18 +126,18 @@ public:
protected:
char * m_Buffer;
- int m_BufferSize; // Total size of the ringbuffer
+ size_t m_BufferSize; // Total size of the ringbuffer
#ifdef _DEBUG
volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker
#endif // _DEBUG
- int m_DataStart; // Where the data starts in the ringbuffer
- int m_WritePos; // Where the data ends in the ringbuffer
- int m_ReadPos; // Where the next read will start in the ringbuffer
+ size_t m_DataStart; // Where the data starts in the ringbuffer
+ size_t m_WritePos; // Where the data ends in the ringbuffer
+ size_t m_ReadPos; // Where the next read will start in the ringbuffer
/// Advances the m_ReadPos by a_Count bytes
- void AdvanceReadPos(int a_Count);
+ void AdvanceReadPos(size_t a_Count);
} ;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 387556775..30e9dbfd4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,3 @@
-
cmake_minimum_required (VERSION 2.8.2)
project (MCServer)
@@ -7,17 +6,17 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
-set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
-
+set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
if (NOT MSVC)
- #Bindings needs to reference other folders so are done here
+ # Bindings need to reference other folders, so they are done here instead
- #lib dependecies are not included
+ # lib dependencies are not included
set(BINDING_DEPENDECIES
+ tolua
${CMAKE_CURRENT_SOURCE_DIR}/Bindings/virtual_method_hooks.lua
${CMAKE_CURRENT_SOURCE_DIR}/Bindings/AllToLua.pkg
Bindings/LuaFunctions.h
@@ -40,6 +39,7 @@ if (NOT MSVC)
BlockEntities/NoteEntity.h
BlockEntities/SignEntity.h
BlockEntities/MobHeadEntity.h
+ BlockEntities/FlowerPotEntity.h
BlockID.h
BoundingBox.h
ChatColor.h
@@ -58,12 +58,14 @@ if (NOT MSVC)
Entities/Player.h
Entities/ProjectileEntity.h
Entities/TNTEntity.h
+ Entities/ExpOrb.h
+ Entities/HangingEntity.h
+ Entities/ItemFrame.h
Generating/ChunkDesc.h
Group.h
Inventory.h
Item.h
ItemGrid.h
- Matrix4f.h
Mobs/Monster.h
OSSupport/File.h
Root.h
@@ -71,9 +73,7 @@ if (NOT MSVC)
StringUtils.h
Tracer.h
UI/Window.h
- Vector3d.h
- Vector3f.h
- Vector3i.h
+ Vector3.h
WebAdmin.h
World.h
)
@@ -95,6 +95,7 @@ if (NOT MSVC)
#add cpp files here
add_library(Bindings
Bindings/Bindings
+ Bindings/DeprecatedBindings
Bindings/LuaChunkStay
Bindings/LuaState
Bindings/LuaWindow
@@ -103,7 +104,6 @@ if (NOT MSVC)
Bindings/PluginLua
Bindings/PluginManager
Bindings/WebPlugin
- Bindings/WebPlugin
)
target_link_libraries(Bindings lua sqlite tolualib)
@@ -137,6 +137,7 @@ if (NOT MSVC)
else ()
+ # MSVC-specific handling: Put all files into one project, separate by the folders:
# Generate the Bindings if they don't exist:
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/Bindings/Bindings.cpp")
@@ -148,6 +149,14 @@ else ()
)
endif()
+ # Get all files in this folder:
+ file(GLOB_RECURSE SOURCE
+ "*.cpp"
+ "*.h"
+ "*.pkg"
+ )
+ source_group("" FILES ${SOURCE})
+
# Add all subfolders as solution-folders:
list(APPEND FOLDERS "Resources")
list(APPEND FOLDERS "Bindings")
@@ -158,23 +167,16 @@ else ()
"${PATH}/*.rc"
"${PATH}/*.pkg"
)
- source_group("${PATH}" FILES ${FOLDER_FILES})
+ string(REPLACE "/" "\\" PROJECT_PATH ${PATH})
+ source_group("${PROJECT_PATH}" FILES ${FOLDER_FILES})
endfunction(includefolder)
foreach(folder ${FOLDERS})
includefolder(${folder})
endforeach(folder)
- file(GLOB_RECURSE SOURCE
- "*.cpp"
- "*.h"
- "*.pkg"
- )
-
include_directories("${PROJECT_SOURCE_DIR}")
- source_group("" FILES ${SOURCE})
-
# Precompiled headers (1st part)
SET_SOURCE_FILES_PROPERTIES(
Globals.cpp PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
@@ -230,7 +232,7 @@ endif ()
if (NOT MSVC)
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
- target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage)
+ target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
endif ()
if (WIN32)
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 8dfbbeef5..22b33c595 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -20,6 +20,7 @@
#include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h"
#include "BlockEntities/MobHeadEntity.h"
+#include "BlockEntities/FlowerPotEntity.h"
#include "Entities/Pickup.h"
#include "Item.h"
#include "Noise.h"
@@ -883,7 +884,7 @@ void cChunk::ApplyWeatherToTop()
FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1);
}
}
- else if (g_BlockIsSnowable[TopBlock])
+ else if (cBlockInfo::IsSnowable(TopBlock) && (Height + 1 < cChunkDef::Height))
{
SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0);
}
@@ -1311,6 +1312,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
+ case E_BLOCK_FLOWER_POT:
{
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{
@@ -1440,6 +1442,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
+ case E_BLOCK_FLOWER_POT:
{
AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break;
@@ -1540,10 +1543,10 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
SetNibble(m_BlockMeta, index, a_BlockMeta);
// ONLY recalculate lighting if it's necessary!
- if(
- (g_BlockLightValue[OldBlockType ] != g_BlockLightValue[a_BlockType]) ||
- (g_BlockSpreadLightFalloff[OldBlockType] != g_BlockSpreadLightFalloff[a_BlockType]) ||
- (g_BlockTransparent[OldBlockType] != g_BlockTransparent[a_BlockType])
+ if (
+ (cBlockInfo::GetLightValue (OldBlockType) != cBlockInfo::GetLightValue (a_BlockType)) ||
+ (cBlockInfo::GetSpreadLightFalloff(OldBlockType) != cBlockInfo::GetSpreadLightFalloff(a_BlockType)) ||
+ (cBlockInfo::IsTransparent (OldBlockType) != cBlockInfo::IsTransparent (a_BlockType))
)
{
m_IsLightValid = false;
@@ -2337,7 +2340,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
-bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
@@ -2369,6 +2372,38 @@ bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMob
+bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
+{
+ // The blockentity list is locked by the parent chunkmap's CS
+ for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
+ {
+ ++itr2;
+ if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
+ {
+ continue;
+ }
+ if ((*itr)->GetBlockType() != E_BLOCK_FLOWER_POT)
+ {
+ // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
+ return false;
+ }
+
+ // The correct block entity is here,
+ if (a_Callback.Item((cFlowerPotEntity *)*itr))
+ {
+ return false;
+ }
+ return true;
+ } // for itr - m_BlockEntitites[]
+
+ // Not found:
+ return false;
+}
+
+
+
+
+
bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
// The blockentity list is locked by the parent chunkmap's CS
@@ -2475,6 +2510,17 @@ cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ)
cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{
+ // If the relative coords are too far away, use the parent's chunk lookup instead:
+ if ((a_RelX < 128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128))
+ {
+ int BlockX = m_PosX * cChunkDef::Width + a_RelX;
+ int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
+ int BlockY, ChunkX, ChunkZ;
+ AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ }
+
+ // Walk the neighbors:
bool ReturnThis = true;
if (a_RelX < 0)
{
diff --git a/src/Chunk.h b/src/Chunk.h
index c9e9697ca..b3fa563cc 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -32,6 +32,7 @@ class cDispenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cBlockArea;
class cPawn;
class cPickup;
@@ -48,7 +49,8 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
@@ -253,8 +255,11 @@ public:
/** 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);
- /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob header block at those coords or callback returns true, returns true if found */
- bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback);
+ /** 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);
+
+ /** 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);
/** 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
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 7be2fa2df..9c7753820 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -9,7 +9,7 @@
#pragma once
-#include "Vector3i.h"
+#include "Vector3.h"
#include "BiomeDef.h"
@@ -62,16 +62,12 @@ typedef unsigned char HEIGHTTYPE;
class cChunkDef
{
public:
- enum
- {
- // Chunk dimensions:
- Width = 16,
- Height = 256,
- NumBlocks = Width * Height * Width,
-
- /// If the data is collected into a single buffer, how large it needs to be:
- BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2), // 2.5 * numblocks
- } ;
+ // Chunk dimensions:
+ static const int Width = 16;
+ static const int Height = 256;
+ static const int NumBlocks = Width * Height * Width;
+ /// If the data is collected into a single buffer, how large it needs to be:
+ static const int BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2); // 2.5 * numblocks
/// The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the highest non-air block in the column
typedef HEIGHTTYPE HeightMap[Width * Width];
@@ -116,7 +112,7 @@ public:
}
- inline static unsigned int MakeIndex(int x, int y, int z )
+ inline static int MakeIndex(int x, int y, int z )
{
if (
(x < Width) && (x > -1) &&
@@ -132,7 +128,7 @@ public:
}
- inline static unsigned int MakeIndexNoCheck(int x, int y, int z)
+ inline static int MakeIndexNoCheck(int x, int y, int z)
{
#if AXIS_ORDER == AXIS_ORDER_XZY
// For some reason, NOT using the Horner schema is faster. Weird.
@@ -255,7 +251,7 @@ public:
ASSERT(!"cChunkDef::SetNibble(): index out of range!");
return;
}
- a_Buffer[a_BlockIdx / 2] = (
+ a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>(
(a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
);
@@ -275,20 +271,20 @@ public:
}
int Index = MakeIndexNoCheck(x, y, z);
- a_Buffer[Index / 2] = (
+ a_Buffer[Index / 2] = static_cast<NIBBLETYPE>(
(a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
);
}
- inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
+ inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
{
return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
}
- inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
+ inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
{
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
}
@@ -306,6 +302,9 @@ The virtual methods are called in the same order as they're declared here.
class cChunkDataCallback abstract
{
public:
+
+ virtual ~cChunkDataCallback() {}
+
/** Called before any other callbacks to inform of the current coords
(only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
If false is returned, the chunk is skipped.
@@ -432,6 +431,9 @@ Used primarily for entity moving while both chunks are locked.
class cClientDiffCallback
{
public:
+
+ virtual ~cClientDiffCallback() {}
+
/// Called for clients that are in Chunk1 and not in Chunk2,
virtual void Removed(cClientHandle * a_Client) = 0;
@@ -492,6 +494,9 @@ typedef std::vector<cChunkCoords> cChunkCoordsVector;
class cChunkCoordCallback
{
public:
+
+ virtual ~cChunkCoordCallback() {}
+
virtual void Call(int a_ChunkX, int a_ChunkZ) = 0;
} ;
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index b5795fbaf..e695f0ab2 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1376,8 +1376,9 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
break;
}
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
- if (itr->BlockType == E_BLOCK_LOG)
+ if ((itr->BlockType == E_BLOCK_LOG) || (itr->BlockType == E_BLOCK_NEW_LOG))
{
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
}
@@ -1784,57 +1785,73 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
switch (Block)
{
- case E_BLOCK_TNT:
- {
- // Activate the TNT, with a random fuse between 10 to 30 game ticks
- double FuseTime = (double)(10 + m_World->GetTickRandomNumber(20)) / 20;
- m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime);
- area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
- a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
- break;
- }
- case E_BLOCK_OBSIDIAN:
- case E_BLOCK_BEDROCK:
- case E_BLOCK_WATER:
- case E_BLOCK_LAVA:
- {
- // These blocks are not affected by explosions
- break;
- }
-
- case E_BLOCK_STATIONARY_WATER:
- {
- // Turn into simulated water:
- area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
- break;
- }
+ case E_BLOCK_TNT:
+ {
+ // Activate the TNT, with a random fuse between 10 to 30 game ticks
+ int FuseTime = 10 + m_World->GetTickRandomNumber(20);
+ m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime);
+ area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
+ a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
+ break;
+ }
+
+ case E_BLOCK_OBSIDIAN:
+ case E_BLOCK_BEDROCK:
+ case E_BLOCK_WATER:
+ case E_BLOCK_LAVA:
+ {
+ // These blocks are not affected by explosions
+ break;
+ }
- case E_BLOCK_STATIONARY_LAVA:
- {
- // Turn into simulated lava:
- area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
- break;
- }
+ case E_BLOCK_STATIONARY_WATER:
+ {
+ // Turn into simulated water:
+ area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
+ break;
+ }
- case E_BLOCK_AIR:
- {
- // No pickups for air
- break;
- }
+ case E_BLOCK_STATIONARY_LAVA:
+ {
+ // Turn into simulated lava:
+ area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
+ break;
+ }
- default:
- {
- if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
+ case E_BLOCK_AIR:
{
- cItems Drops;
- cBlockHandler * Handler = BlockHandler(Block);
+ // No pickups for air
+ break;
+ }
- Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc.
- m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z);
+ default:
+ {
+ if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
+ {
+ cItems Drops;
+ cBlockHandler * Handler = BlockHandler(Block);
+
+ Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc.
+ m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z);
+ }
+ else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around
+ {
+ if (!cBlockInfo::FullyOccupiesVoxel(Block))
+ {
+ break;
+ }
+ else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL)))
+ {
+ break;
+ }
+ m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z));
+ }
+
+ area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
+ a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
+ break;
+
}
- area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
- a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
- }
} // switch (BlockType)
} // for z
} // for y
@@ -1846,11 +1863,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
public cEntityCallback
{
public:
- cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize, int a_ExplosionSizeSq) :
+ cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize) :
m_bbTNT(a_bbTNT),
m_ExplosionPos(a_ExplosionPos),
- m_ExplosionSize(a_ExplosionSize),
- m_ExplosionSizeSq(a_ExplosionSizeSq)
+ m_ExplosionSize(a_ExplosionSize)
{
}
@@ -1873,14 +1889,16 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
}
Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z));
- Vector3d MaxExplosionBoundary(m_ExplosionSizeSq, m_ExplosionSizeSq, m_ExplosionSizeSq);
// Work out how far we are from the edge of the TNT's explosive effect
AbsoluteEntityPos -= m_ExplosionPos;
- AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos;
- double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize;
- FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage);
+ // All to positive
+ AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x);
+ AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y);
+ AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z);
+
+ double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize;
// Clip damage values
if (FinalDamage > a_Entity->GetMaxHealth())
@@ -1888,7 +1906,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
else if (FinalDamage < 0)
FinalDamage = 0;
- if (!a_Entity->IsTNT()) // Don't apply damage to other TNT entities, they should be invincible
+ if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
{
a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
}
@@ -1898,7 +1916,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
if (distance_explosion.SqrLength() < 4096.0)
{
distance_explosion.Normalize();
- distance_explosion *= m_ExplosionSizeSq;
+ distance_explosion *= m_ExplosionSize * m_ExplosionSize;
a_Entity->AddSpeed(distance_explosion);
}
@@ -1910,14 +1928,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
cBoundingBox & m_bbTNT;
Vector3d m_ExplosionPos;
int m_ExplosionSize;
- int m_ExplosionSizeSq;
};
cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1);
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2);
- cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt, ExplosionSizeSq);
+ cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt);
ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):
@@ -2182,7 +2199,25 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
-bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
+{
+ int ChunkX, ChunkZ;
+ int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
+ cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ cCSLock Lock(m_CSLayers);
+ cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ if ((Chunk == NULL) && !Chunk->IsValid())
+ {
+ return false;
+ }
+ return Chunk->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
+bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@@ -2193,7 +2228,7 @@ bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
{
return false;
}
- return Chunk->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+ return Chunk->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 9df68c403..9d973f2a9 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -26,6 +26,7 @@ class cFurnaceEntity;
class cNoteEntity;
class cCommandBlockEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cPawn;
class cPickup;
class cChunkDataSerializer;
@@ -41,10 +42,11 @@ typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cChunk> cChunkCallback;
@@ -257,7 +259,10 @@ public:
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 */
- bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); // Lua-accessible
+ 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 */
+ 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 */
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
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index dd2116dbf..23ba4dbab 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -22,9 +22,6 @@
#include "Blocks/BlockSlab.h"
#include "Blocks/ChunkInterface.h"
-#include "Vector3f.h"
-#include "Vector3d.h"
-
#include "Root.h"
#include "Authenticator.h"
@@ -36,22 +33,12 @@
-
-
-#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
- case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
- case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
-
-
-
-
-
-/** If the number of queued outgoing packets reaches this, the client will be kicked */
-#define MAX_OUTGOING_PACKETS 2000
-
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
#define MAX_EXPLOSIONS_PER_TICK 20
+/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
+#define MAX_BLOCK_CHANGE_INTERACTIONS 20
+
/** How many ticks before the socket is closed after the client is destroyed (#31) */
static const int TICKS_BEFORE_CLOSE = 20;
@@ -96,8 +83,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_ShouldCheckDownloaded(false),
m_NumExplosionsThisTick(0),
m_UniqueID(0),
- m_Locale("en_GB"),
- m_HasSentPlayerChunk(false)
+ m_HasSentPlayerChunk(false),
+ m_Locale("en_GB")
{
m_Protocol = new cProtocolRecognizer(this);
@@ -555,12 +542,25 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
}
else if (a_Channel == "REGISTER")
{
+ if (HasPluginChannel(a_Channel))
+ {
+ SendPluginMessage("UNREGISTER", a_Channel);
+ return; // Can't register again if already taken - kinda defeats the point of plugin messaging!
+ }
+
RegisterPluginChannels(BreakApartPluginChannels(a_Message));
}
else if (a_Channel == "UNREGISTER")
{
UnregisterPluginChannels(BreakApartPluginChannels(a_Message));
}
+ else if (!HasPluginChannel(a_Channel))
+ {
+ // Ignore if client sent something but didn't register the channel first
+ LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", GetUsername().c_str(), a_Channel.c_str());
+ SendPluginMessage("UNREGISTER", a_Channel);
+ return;
+ }
cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message);
}
@@ -687,6 +687,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
);
+ m_NumBlockChangeInteractionsThisTick++;
+
+ if (!CheckBlockInteractionsRate())
+ {
+ Kick("Too many blocks were destroyed per unit time - hacked client?");
+ return;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
{
@@ -694,12 +702,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
-
- if (!CheckBlockInteractionsRate())
- {
- // Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block
- return;
- }
switch (a_Status)
{
@@ -819,7 +821,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
if (
(m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately
- g_BlockOneHitDig[a_OldBlock] // One-hit blocks get destroyed immediately, too
+ cBlockInfo::IsOneHitDig(a_OldBlock) // One-hit blocks get destroyed immediately, too
)
{
HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta);
@@ -838,7 +840,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
cWorld * World = m_Player->GetWorld();
cChunkInterface ChunkInterface(World->GetChunkMap());
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(a_OldBlock);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock);
Handler->OnDigging(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@@ -852,7 +854,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
int pZ = a_BlockZ;
AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false)
- Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ));
+ Handler = cBlockInfo::GetHandler(World->GetBlock(pX, pY, pZ));
if (Handler->IsClickedThrough())
{
@@ -877,7 +879,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
LOGD("Prevented a dig/aim bug in the client (finish {%d, %d, %d} vs start {%d, %d, %d}, HSD: %s)",
a_BlockX, a_BlockY, a_BlockZ,
m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ,
- m_HasStartedDigging
+ (m_HasStartedDigging ? "True" : "False")
);
return;
}
@@ -920,21 +922,31 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
);
+ cWorld * World = m_Player->GetWorld();
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
// A plugin doesn't agree with the action, replace the block on the client and quit:
- if (a_BlockFace > -1)
+ cChunkInterface ChunkInterface(World->GetChunkMap());
+ BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
+ BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+
+ if (a_BlockFace != BLOCK_FACE_NONE)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things
}
return;
}
+
+ m_NumBlockChangeInteractionsThisTick++;
if (!CheckBlockInteractionsRate())
{
- LOGD("Too many block interactions, aborting placement");
+ Kick("Too many blocks were placed/interacted with per unit time - hacked client?");
return;
}
@@ -950,20 +962,18 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
);
// Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block
- if (a_BlockFace > -1)
+ if (a_BlockFace != BLOCK_FACE_NONE)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
}
return;
}
-
- cWorld * World = m_Player->GetWorld();
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{
@@ -980,7 +990,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
- if (ItemHandler->IsPlaceable() && (a_BlockFace > -1))
+ if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
{
HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
}
@@ -1018,6 +1028,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler)
{
+ BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
if (a_BlockFace < 0)
{
// Clicked in air
@@ -1028,7 +1039,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
BLOCKTYPE ClickedBlock;
NIBBLETYPE ClickedBlockMeta;
- BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage);
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
@@ -1045,8 +1055,8 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab?
((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type?
(
- (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
- (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
+ (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
+ (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
)
)
{
@@ -1054,7 +1064,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
// If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y)
// Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason
// Don't touch coordinates if anything else because a dblslab opportunity is present
- if((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP))
+ if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP))
{
++a_BlockY;
}
@@ -1130,7 +1140,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
// The actual block placement:
World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- if (m_Player->GetGameMode() != gmCreative)
+ if (!m_Player->IsGameModeCreative())
{
m_Player->GetInventory().RemoveOneEquippedItem();
}
@@ -1447,7 +1457,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
-void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
+void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -1455,35 +1465,37 @@ void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
return;
}
- switch (a_ActionID)
+ m_Player->SetCrouch(a_IsCrouching);
+}
+
+
+
+
+
+void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
{
- case 1: // Crouch
- {
- m_Player->SetCrouch(true);
- break;
- }
- case 2: // Uncrouch
- {
- m_Player->SetCrouch(false);
- break;
- }
- case 3: // Leave bed
- {
- m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
- break;
- }
- case 4: // Start sprinting
- {
- m_Player->SetSprint(true);
- break;
- }
- case 5: // Stop sprinting
- {
- m_Player->SetSprint(false);
- SendPlayerMaxSpeed();
- break;
- }
+ // We should only receive entity actions from the entity that is performing the action
+ return;
}
+
+ m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
+}
+
+
+
+
+
+void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
+ {
+ // We should only receive entity actions from the entity that is performing the action
+ return;
+ }
+
+ m_Player->SetSprint(a_IsSprinting);
}
@@ -1596,10 +1608,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[]
- // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock
- // Instead, the chunks will be streamed when the client is moved to the new world's Tick list,
- // by setting state to csAuthenticated
- m_State = csAuthenticated;
+ // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set
+ // Meanwhile here, we set last streamed values to bogus ones so everything is resent
m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff;
m_HasSentPlayerChunk = false;
@@ -1613,28 +1623,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
{
ASSERT(m_Player != NULL);
ASSERT(m_Player->GetWorld() != NULL);
- /*
- // TODO: _X 2012_11_01: This needs a total re-thinking and rewriting
- int LastActionCnt = m_Player->GetLastBlockActionCnt();
- if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1)
- {
- // Limit the number of block interactions per tick
- m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
- m_Player->SetLastBlockActionCnt(LastActionCnt + 1);
- if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS)
- {
- // Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
- LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str());
- Kick("You're a baaaaaad boy!");
- return false;
- }
- }
- else
+
+ if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS)
{
- m_Player->SetLastBlockActionCnt(0); // Reset count
- m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time.
+ return false;
}
- */
+
return true;
}
@@ -1707,8 +1701,9 @@ void cClientHandle::Tick(float a_Dt)
}
}
- // Reset explosion counter:
+ // Reset explosion & block change counters:
m_NumExplosionsThisTick = 0;
+ m_NumBlockChangeInteractionsThisTick = 0;
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 194533402..5496e61a7 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -12,7 +12,7 @@
#define CCLIENTHANDLE_H_INCLUDED
#include "Defines.h"
-#include "Vector3d.h"
+#include "Vector3.h"
#include "OSSupport/SocketThreads.h"
#include "ChunkDef.h"
#include "ByteBuffer.h"
@@ -46,7 +46,6 @@ class cClientHandle : // tolua_export
public cSocketThreads::cCallback
{ // tolua_export
public:
- static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
#if defined(ANDROID_NDK)
static const int DEFAULT_VIEW_DISTANCE = 4; // The default ViewDistance (used when no value is set in Settings.ini)
@@ -188,7 +187,9 @@ public:
void HandleChat (const AString & a_Message);
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
void HandleDisconnect (const AString & a_Reason);
- void HandleEntityAction (int a_EntityID, char a_ActionID);
+ void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
+ void HandleEntityLeaveBed (int a_EntityID);
+ void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
/** Called when the protocol handshake has been received (for protocol versions that support it;
otherwise the first instant when a username is received).
@@ -229,10 +230,10 @@ public:
/** Called when the player moves into a different world; queues sreaming the new chunks */
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
+private:
+
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);
-
-private:
/** The type used for storing the names of registered plugin channels. */
typedef std::set<AString> cChannels;
@@ -319,6 +320,9 @@ private:
/** Number of explosions sent this tick */
int m_NumExplosionsThisTick;
+
+ /** Number of place or break interactions this tick */
+ int m_NumBlockChangeInteractionsThisTick;
static int s_ClientCount;
int m_UniqueID;
diff --git a/src/CommandOutput.cpp b/src/CommandOutput.cpp
index c221682a1..2c116b3d6 100644
--- a/src/CommandOutput.cpp
+++ b/src/CommandOutput.cpp
@@ -51,7 +51,7 @@ void cLogCommandOutputCallback::Finished(void)
{
case '\n':
{
- LOG(m_Buffer.substr(last, i - last).c_str());
+ LOG("%s", m_Buffer.substr(last, i - last).c_str());
last = i + 1;
break;
}
@@ -59,7 +59,7 @@ void cLogCommandOutputCallback::Finished(void)
} // for i - m_Buffer[]
if (last < len)
{
- LOG(m_Buffer.substr(last).c_str());
+ LOG("%s", m_Buffer.substr(last).c_str());
}
// Clear the buffer for the next command output:
diff --git a/src/CommandOutput.h b/src/CommandOutput.h
index 3763d625f..5682b4fd8 100644
--- a/src/CommandOutput.h
+++ b/src/CommandOutput.h
@@ -17,7 +17,7 @@ public:
virtual ~cCommandOutputCallback() {}; // Force a virtual destructor in subclasses
/// Syntax sugar function, calls Out() with Printf()-ed parameters; appends a "\n"
- void Out(const char * a_Fmt, ...);
+ void Out(const char * a_Fmt, ...) FORMATSTRING(2, 3);
/// Called when the command wants to output anything; may be called multiple times
virtual void Out(const AString & a_Text) = 0;
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
index 3eec35657..c70ef1070 100644
--- a/src/CompositeChat.cpp
+++ b/src/CompositeChat.cpp
@@ -10,7 +10,7 @@
-#if SELF_TEST
+#ifdef SELF_TEST
/** A simple self-test that verifies that the composite chat parser is working properly. */
class SelfTest_CompositeChat
@@ -32,15 +32,15 @@ public:
cCompositeChat Msg;
Msg.ParseText("Testing @2color codes and http://links parser");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 4);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[3]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "@2");
- assert(Parts[2]->m_Style == "@2");
- assert(Parts[3]->m_Style == "@2");
+ assert_test(Parts.size() == 4);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "@2");
+ assert_test(Parts[2]->m_Style == "@2");
+ assert_test(Parts[3]->m_Style == "@2");
}
void TestParser2(void)
@@ -48,15 +48,15 @@ public:
cCompositeChat Msg;
Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 4);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[3]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "@3");
- assert(Parts[1]->m_Style == "@5");
- assert(Parts[2]->m_Style == "@5");
- assert(Parts[3]->m_Style == "@5");
+ assert_test(Parts.size() == 4);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "@3");
+ assert_test(Parts[1]->m_Style == "@5");
+ assert_test(Parts[2]->m_Style == "@5");
+ assert_test(Parts[3]->m_Style == "@5");
}
void TestParser3(void)
@@ -64,11 +64,11 @@ public:
cCompositeChat Msg;
Msg.ParseText("http://links.starting the text");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 2);
- assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "");
+ assert_test(Parts.size() == 2);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "");
}
void TestParser4(void)
@@ -76,11 +76,11 @@ public:
cCompositeChat Msg;
Msg.ParseText("links finishing the text: http://some.server");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 2);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "");
+ assert_test(Parts.size() == 2);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "");
}
void TestParser5(void)
@@ -88,9 +88,9 @@ public:
cCompositeChat Msg;
Msg.ParseText("http://only.links");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 1);
- assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[0]->m_Style == "");
+ assert_test(Parts.size() == 1);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[0]->m_Style == "");
}
} gTest;
@@ -112,8 +112,8 @@ cCompositeChat::cCompositeChat(void) :
-cCompositeChat::cCompositeChat(const AString & a_ParseText) :
- m_MessageType(mtCustom)
+cCompositeChat::cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType) :
+ m_MessageType(a_MessageType)
{
ParseText(a_ParseText);
}
@@ -314,6 +314,58 @@ void cCompositeChat::UnderlineUrls(void)
+AString cCompositeChat::ExtractText(void) const
+{
+ AString Msg;
+ for (cParts::const_iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr)
+ {
+ switch ((*itr)->m_PartType)
+ {
+ case ptText:
+ case ptClientTranslated:
+ case ptRunCommand:
+ case ptSuggestCommand:
+ {
+ Msg.append((*itr)->m_Text);
+ break;
+ }
+ case ptUrl:
+ {
+ Msg.append(((cUrlPart *)(*itr))->m_Url);
+ break;
+ }
+ } // switch (PartType)
+ } // for itr - m_Parts[]
+ return Msg;
+}
+
+
+
+
+
+cMCLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType)
+{
+ switch (a_MessageType)
+ {
+ case mtCustom: return cMCLogger::llRegular;
+ case mtFailure: return cMCLogger::llWarning;
+ case mtInformation: return cMCLogger::llInfo;
+ case mtSuccess: return cMCLogger::llRegular;
+ case mtWarning: return cMCLogger::llWarning;
+ case mtFatal: return cMCLogger::llError;
+ case mtDeath: return cMCLogger::llRegular;
+ case mtPrivateMessage: return cMCLogger::llRegular;
+ case mtJoin: return cMCLogger::llRegular;
+ case mtLeave: return cMCLogger::llRegular;
+ }
+ ASSERT(!"Unhandled MessageType");
+ return cMCLogger::llError;
+}
+
+
+
+
+
void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle)
{
if (a_AddStyle.empty())
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
index 51600da4f..5b9c5f612 100644
--- a/src/CompositeChat.h
+++ b/src/CompositeChat.h
@@ -117,21 +117,22 @@ public:
/** Creates a new chat message and parses the text into parts.
Recognizes "http:" and "https:" links and @color-codes.
Uses ParseText() for the actual parsing. */
- cCompositeChat(const AString & a_ParseText);
+ cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom);
~cCompositeChat();
/** Removes all parts from the object. */
void Clear(void);
+ // tolua_end
+
+ // The following are exported in ManualBindings in order to support chaining - they return *this in Lua (#755)
+
/** Adds a plain text part, with optional style.
The default style is plain white text. */
void AddTextPart(const AString & a_Message, const AString & a_Style = "");
- // tolua_end
-
- /** Adds a part that is translated client-side, with the formatting parameters and optional style.
- Exported in ManualBindings due to AStringVector usage - Lua uses an array-table of strings. */
+ /** Adds a part that is translated client-side, with the formatting parameters and optional style. */
void AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = "");
// tolua_begin
@@ -155,16 +156,27 @@ public:
/** Sets the message type, which is indicated by prefixes added to the message when serializing. */
void SetMessageType(eMessageType a_MessageType);
+ /** Adds the "underline" style to each part that is an URL. */
+ void UnderlineUrls(void);
+
+ // tolua_begin
+
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
- /** Adds the "underline" style to each part that is an URL. */
- void UnderlineUrls(void);
+ /** Returns the text from the parts that comprises the human-readable data.
+ Used for older protocols that don't support composite chat
+ and for console-logging. */
+ AString ExtractText(void) const;
// tolua_end
const cParts & GetParts(void) const { return m_Parts; }
+ /** Converts the MessageType to a LogLevel value.
+ Used by the logging bindings when logging a cCompositeChat object. */
+ static cMCLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType);
+
protected:
/** All the parts that */
cParts m_Parts;
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index fb1a10cca..30e7a8733 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -1,4 +1,4 @@
-
+
// CraftingRecipes.cpp
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
@@ -192,7 +192,9 @@ void cCraftingGrid::Dump(void)
{
for (int y = 0; y < m_Height; y++) for (int x = 0; x < m_Width; x++)
{
+ #ifdef _DEBUG
int idx = x + m_Width * y;
+ #endif
LOGD("Slot (%d, %d): Type %d, health %d, count %d",
x, y, m_Items[idx].m_ItemType, m_Items[idx].m_ItemDamage, m_Items[idx].m_ItemCount
);
@@ -338,7 +340,7 @@ void cCraftingRecipes::LoadRecipes(void)
}
AddRecipeLine(LineNum, Recipe);
} // for itr - Split[]
- LOG("Loaded %d crafting recipes", m_Recipes.size());
+ LOG("Loaded " SIZE_T_FMT " crafting recipes", m_Recipes.size());
}
@@ -762,9 +764,94 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
Recipe->m_Ingredients.push_back(*itrS);
}
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
+
+ // We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
+ HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);
+
return Recipe.release();
}
+
+void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY)
+{
+ // TODO: add support for more than one dye in the recipe
+ // A manual and temporary solution (listing everything) is in crafting.txt for fade colours, but a programmatic solutions needs to be done for everything else
+
+ if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_ROCKET)
+ {
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was a rocket, found a star - copy star data to rocket data
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_GUNPOWDER:
+ {
+ // Gunpowder - increase flight time
+ a_Recipe->m_Result.m_FireworkItem.m_FlightTimeInTicks += 20;
+ break;
+ }
+ case E_ITEM_PAPER: break;
+ default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
+ }
+ }
+ }
+ else if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_STAR)
+ {
+ std::vector<int> DyeColours;
+ bool FoundStar = false;
+
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was star, found another star - probably adding fade colours, but copy data over anyhow
+ FoundStar = true;
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_DYE:
+ {
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
+ break;
+ }
+ case E_ITEM_GUNPOWDER: break;
+ case E_ITEM_DIAMOND: a_Recipe->m_Result.m_FireworkItem.m_HasTrail = true; break;
+ case E_ITEM_GLOWSTONE_DUST: a_Recipe->m_Result.m_FireworkItem.m_HasFlicker = true; break;
+
+ case E_ITEM_FIRE_CHARGE: a_Recipe->m_Result.m_FireworkItem.m_Type = 1; break;
+ case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
+ case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
+ case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
+ default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
+ }
+ }
+
+ if (FoundStar && (!DyeColours.empty()))
+ {
+ // Found a star and a dye? Fade colours.
+ a_Recipe->m_Result.m_FireworkItem.m_FadeColours = DyeColours;
+ }
+ else if (!DyeColours.empty())
+ {
+ // Only dye? Normal colours.
+ a_Recipe->m_Result.m_FireworkItem.m_Colours = DyeColours;
+ }
+ }
+}
+
+
+
+
diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h
index 9d92cbfab..90e41eddc 100644
--- a/src/CraftingRecipes.h
+++ b/src/CraftingRecipes.h
@@ -165,6 +165,9 @@ protected:
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
+
+ /** Searches for anything firework related, and does the data setting if appropriate */
+ void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY);
} ;
diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp
index 782837b23..3e5240248 100644
--- a/src/Cuboid.cpp
+++ b/src/Cuboid.cpp
@@ -38,6 +38,20 @@ void cCuboid::Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2)
+void cCuboid::Assign(const cCuboid & a_SrcCuboid)
+{
+ p1.x = a_SrcCuboid.p1.x;
+ p1.y = a_SrcCuboid.p1.y;
+ p1.z = a_SrcCuboid.p1.z;
+ p2.x = a_SrcCuboid.p2.x;
+ p2.y = a_SrcCuboid.p2.y;
+ p2.z = a_SrcCuboid.p2.z;
+}
+
+
+
+
+
void cCuboid::Sort(void)
{
if (p1.x > p2.x)
@@ -72,6 +86,9 @@ int cCuboid::GetVolume(void) const
bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
{
+ ASSERT(IsSorted());
+ ASSERT(a_Other.IsSorted());
+
// In order for cuboids to intersect, each of their coord intervals need to intersect
return (
DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) &&
@@ -86,6 +103,9 @@ bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const
{
+ ASSERT(IsSorted());
+ ASSERT(a_Outer.IsSorted());
+
return (
(p1.x >= a_Outer.p1.x) &&
(p2.x <= a_Outer.p2.x) &&
@@ -197,3 +217,37 @@ bool cCuboid::IsSorted(void) const
+
+void cCuboid::Engulf(const Vector3i & a_Point)
+{
+ if (a_Point.x < p1.x)
+ {
+ p1.x = a_Point.x;
+ }
+ else if (a_Point.x > p2.x)
+ {
+ p2.x = a_Point.x;
+ }
+
+ if (a_Point.y < p1.y)
+ {
+ p1.y = a_Point.y;
+ }
+ else if (a_Point.y > p2.y)
+ {
+ p2.y = a_Point.y;
+ }
+
+ if (a_Point.z < p1.z)
+ {
+ p1.z = a_Point.z;
+ }
+ else if (a_Point.z > p2.z)
+ {
+ p2.z = a_Point.z;
+ }
+}
+
+
+
+
diff --git a/src/Cuboid.h b/src/Cuboid.h
index 51ccf799b..3239c54fc 100644
--- a/src/Cuboid.h
+++ b/src/Cuboid.h
@@ -1,8 +1,7 @@
#pragma once
-#include "Vector3i.h"
-#include "Vector3d.h"
+#include "Vector3.h"
@@ -22,6 +21,7 @@ public:
cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) {}
void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2);
+ void Assign(const cCuboid & a_SrcCuboid);
void Sort(void);
@@ -34,7 +34,8 @@ public:
Works on unsorted cuboids, too. */
int GetVolume(void) const;
- /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. */
+ /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive.
+ Assumes both cuboids are sorted. */
bool DoesIntersect(const cCuboid & a_Other) const;
bool IsInside(const Vector3i & v) const
@@ -64,7 +65,8 @@ public:
);
}
- /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords) */
+ /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords).
+ Assumes both cuboids are sorted. */
bool IsCompletelyInside(const cCuboid & a_Outer) const;
/** Moves the cuboid by the specified offsets in each direction */
@@ -72,7 +74,7 @@ public:
/** Expands the cuboid by the specified amount in each direction.
Works on unsorted cuboids as well.
- Note that this function doesn't check for underflows. */
+ Note that this function doesn't check for underflows when using negative amounts. */
void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
/** Clamps both X coords to the specified range. Works on unsorted cuboids, too. */
@@ -86,6 +88,9 @@ public:
/** Returns true if the coords are properly sorted (lesser in p1, greater in p2) */
bool IsSorted(void) const;
+
+ /** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */
+ void Engulf(const Vector3i & a_Point);
} ;
// tolua_end
diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp
index c42d09b89..322084dc4 100644
--- a/src/DeadlockDetect.cpp
+++ b/src/DeadlockDetect.cpp
@@ -7,7 +7,7 @@
#include "DeadlockDetect.h"
#include "Root.h"
#include "World.h"
-# include <cstdlib>
+#include <cstdlib>
@@ -16,9 +16,6 @@
/// Number of milliseconds per cycle
const int CYCLE_MILLISECONDS = 100;
-/// When the number of cycles for the same world age hits this value, it is considered a deadlock
-const int NUM_CYCLES_LIMIT = 200; // 200 = twenty seconds
-
@@ -121,7 +118,6 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
if (itr->second.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS)
{
DeadlockDetected();
- return;
}
}
else
diff --git a/src/DeadlockDetect.h b/src/DeadlockDetect.h
index cb2309169..6aa98acbb 100644
--- a/src/DeadlockDetect.h
+++ b/src/DeadlockDetect.h
@@ -60,7 +60,7 @@ protected:
void CheckWorldAge(const AString & a_WorldName, Int64 a_Age);
/// Called when a deadlock is detected. Aborts the server.
- void DeadlockDetected(void);
+ NORETURN void DeadlockDetected(void);
} ;
diff --git a/src/Defines.h b/src/Defines.h
index ba2866f83..1a8b3fa4a 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -2,6 +2,7 @@
#pragma once
#include "ChatColor.h"
+#include <limits>
@@ -17,33 +18,6 @@ typedef std::vector<int> cSlotNums;
// tolua_begin
-/// How much light do the blocks emit on their own?
-extern unsigned char g_BlockLightValue[];
-
-/// How much light do the block consume?
-extern unsigned char g_BlockSpreadLightFalloff[];
-
-/// Is a block completely transparent? (light doesn't get decreased(?))
-extern bool g_BlockTransparent[];
-
-/// Is a block destroyed after a single hit?
-extern bool g_BlockOneHitDig[];
-
-/// Can a piston break this block?
-extern bool g_BlockPistonBreakable[256];
-
-/// Can this block hold snow atop?
-extern bool g_BlockIsSnowable[256];
-
-/// Does this block require a tool to drop?
-extern bool g_BlockRequiresSpecialTool[256];
-
-/// Is this block solid (player cannot walk through)?
-extern bool g_BlockIsSolid[256];
-
-/// Does this block fully occupy it's voxel - is it a 'full' block?
-extern bool g_BlockFullyOccupiesVoxel[256];
-
/// Experience Orb setup
enum
{
@@ -253,6 +227,79 @@ inline const char * ClickActionToString(eClickAction a_ClickAction)
+/** Returns a blockface mirrored around the Y axis (doesn't change up/down). */
+inline eBlockFace MirrorBlockFaceY(eBlockFace a_BlockFace)
+{
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_XM: return BLOCK_FACE_XP;
+ case BLOCK_FACE_XP: return BLOCK_FACE_XM;
+ case BLOCK_FACE_ZM: return BLOCK_FACE_ZP;
+ case BLOCK_FACE_ZP: return BLOCK_FACE_ZM;
+ default: return a_BlockFace;
+ }
+}
+
+
+
+
+
+/** Returns a blockface rotated around the Y axis counter-clockwise. */
+inline eBlockFace RotateBlockFaceCCW(eBlockFace a_BlockFace)
+{
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_XM: return BLOCK_FACE_ZP;
+ case BLOCK_FACE_XP: return BLOCK_FACE_ZM;
+ case BLOCK_FACE_ZM: return BLOCK_FACE_XM;
+ case BLOCK_FACE_ZP: return BLOCK_FACE_XP;
+ default: return a_BlockFace;
+ }
+}
+
+
+
+
+
+inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace)
+{
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_XM: return BLOCK_FACE_ZM;
+ case BLOCK_FACE_XP: return BLOCK_FACE_ZP;
+ case BLOCK_FACE_ZM: return BLOCK_FACE_XP;
+ case BLOCK_FACE_ZP: return BLOCK_FACE_XM;
+ default: return a_BlockFace;
+ }
+}
+
+
+
+
+
+/** Returns the textual representation of the BlockFace constant. */
+inline AString BlockFaceToString(eBlockFace a_BlockFace)
+{
+ 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";
+ case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE";
+ }
+ // clang optimisises this line away then warns that it has done so.
+ #if !defined(__clang__)
+ return Printf("Unknown BLOCK_FACE: %d", a_BlockFace);
+ #endif
+}
+
+
+
+
+
inline bool IsValidBlock(int a_BlockType)
{
if (
@@ -446,7 +493,7 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
{
- if (a_X != 0)
+ if (fabs(a_X) < std::numeric_limits<double>::epsilon())
{
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
}
@@ -486,16 +533,22 @@ enum eMessageType
// http://forum.mc-server.org/showthread.php?tid=1212
// MessageType...
- mtCustom, // Send raw data without any processing
- mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
- mtInformation, // Informational message (i.e. command usage)
- mtSuccess, // Something executed successfully
- mtWarning, // Something concerning (i.e. reload) is about to happen
- mtFatal, // Something catastrophic occured (i.e. plugin crash)
- mtDeath, // Denotes death of player
- mtPrivateMessage, // Player to player messaging identifier
- mtJoin, // A player has joined the server
- mtLeave, // A player has left the server
+ mtCustom, // Send raw data without any processing
+ mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
+ mtInformation, // Informational message (i.e. command usage)
+ mtSuccess, // Something executed successfully
+ mtWarning, // Something concerning (i.e. reload) is about to happen
+ mtFatal, // Something catastrophic occured (i.e. plugin crash)
+ mtDeath, // Denotes death of player
+ mtPrivateMessage, // Player to player messaging identifier
+ mtJoin, // A player has joined the server
+ mtLeave, // A player has left the server
+
+ // Common aliases:
+ mtFail = mtFailure,
+ mtError = mtFailure,
+ mtInfo = mtInformation,
+ mtPM = mtPrivateMessage,
};
@@ -654,7 +707,7 @@ namespace ItemCategory
inline bool BlockRequiresSpecialTool(BLOCKTYPE a_BlockType)
{
if(!IsValidBlock(a_BlockType)) return false;
- return g_BlockRequiresSpecialTool[a_BlockType];
+ return cBlockInfo::RequiresSpecialTool(a_BlockType);
}
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 94b24c5af..921252253 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -122,5 +122,3 @@ void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
AddSpeed(ToAddSpeed);
}
-
- \ No newline at end of file
diff --git a/src/Entities/Effects.h b/src/Entities/Effects.h
index e7611847d..baf3302fb 100644
--- a/src/Entities/Effects.h
+++ b/src/Entities/Effects.h
@@ -27,4 +27,4 @@ enum ENUM_ENTITY_EFFECT
E_EFFECT_ABSORPTION = 22,
E_EFFECT_SATURATION = 23,
} ;
-// tolua_end \ No newline at end of file
+// tolua_end
diff --git a/src/Entities/EnderCrystal.cpp b/src/Entities/EnderCrystal.cpp
new file mode 100644
index 000000000..a640b236c
--- /dev/null
+++ b/src/Entities/EnderCrystal.cpp
@@ -0,0 +1,56 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "EnderCrystal.h"
+#include "ClientHandle.h"
+#include "Player.h"
+#include "../Chunk.h"
+
+
+
+
+
+cEnderCrystal::cEnderCrystal(double a_X, double a_Y, double a_Z)
+ : cEntity(etEnderCrystal, a_X, a_Y, a_Z, 1.0, 1.0)
+{
+ SetMaxHealth(5);
+}
+
+
+
+
+
+void cEnderCrystal::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ a_ClientHandle.SendSpawnObject(*this, 51, 0, (Byte)GetYaw(), (Byte)GetPitch());
+}
+
+
+
+
+
+void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ UNUSED(a_Dt);
+
+ a_Chunk.SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_FIRE, 0);
+
+ // No further processing (physics e.t.c.) is needed
+}
+
+
+
+
+
+void cEnderCrystal::KilledBy(cEntity * a_Killer)
+{
+ super::KilledBy(a_Killer);
+
+ m_World->DoExplosionAt(6.0, GetPosX(), GetPosY(), GetPosZ(), true, esEnderCrystal, this);
+
+ Destroy();
+}
+
+
+
+
diff --git a/src/Entities/EnderCrystal.h b/src/Entities/EnderCrystal.h
new file mode 100644
index 000000000..5b86df987
--- /dev/null
+++ b/src/Entities/EnderCrystal.h
@@ -0,0 +1,33 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cEnderCrystal :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cEnderCrystal);
+
+ cEnderCrystal(double a_X, double a_Y, double a_Z);
+
+private:
+
+ // cEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(cEntity * a_Killer) override;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 8554ab2a5..221cbbea7 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -4,7 +4,7 @@
#include "../World.h"
#include "../Server.h"
#include "../Root.h"
-#include "../Matrix4f.h"
+#include "../Matrix4.h"
#include "../ClientHandle.h"
#include "../Chunk.h"
#include "../Simulator/FluidSimulator.h"
@@ -521,27 +521,35 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
if (a_Chunk.IsValid())
{
- HandlePhysics(a_Dt, a_Chunk);
- }
- }
- if (a_Chunk.IsValid())
- {
- TickBurning(a_Chunk);
- }
- if ((a_Chunk.IsValid()) && (GetPosY() < -46))
- {
- TickInVoid(a_Chunk);
- }
- else
- m_TicksSinceLastVoidDamage = 0;
+ cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
- if (IsMob() || IsPlayer())
- {
- // Set swimming state
- SetSwimState(a_Chunk);
+ if ((NextChunk == NULL) || !NextChunk->IsValid())
+ {
+ return;
+ }
+
+ TickBurning(*NextChunk);
+
+ if (GetPosY() < VOID_BOUNDARY)
+ {
+ TickInVoid(*NextChunk);
+ }
+ else
+ {
+ m_TicksSinceLastVoidDamage = 0;
+ }
+
+ if (IsMob() || IsPlayer())
+ {
+ // Set swimming state
+ SetSwimState(*NextChunk);
- // Handle drowning
- HandleAir();
+ // Handle drowning
+ HandleAir();
+ }
+
+ HandlePhysics(a_Dt, *NextChunk);
+ }
}
}
@@ -562,7 +570,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{
// Outside of the world
-
+
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
// See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL)
@@ -571,210 +579,205 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos);
}
+
return;
}
- // Make sure we got the correct chunk and a valid one. No one ever knows...
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- if (NextChunk != NULL)
+ int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
+ int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
+ BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ );
+ BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
+ if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{
- int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
- int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
- BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
- if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block
+ if (m_bOnGround) // check if it's still on the ground
{
- if (m_bOnGround) // check if it's still on the ground
+ if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water.
{
- if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water.
- {
- m_bOnGround = false;
- }
+ m_bOnGround = false;
}
}
- else
- {
- // Push out entity.
- BLOCKTYPE GotBlock;
+ }
+ else
+ {
+ // Push out entity.
+ BLOCKTYPE GotBlock;
- static const struct
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0},
- {-1, 0, 0},
- { 0, 0, 1},
- { 0, 0, -1},
- } ;
-
- bool IsNoAirSurrounding = true;
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ static const struct
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0},
+ {-1, 0, 0},
+ { 0, 0, 1},
+ { 0, 0, -1},
+ } ;
+
+ bool IsNoAirSurrounding = true;
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
{
- if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
- {
- // The pickup is too close to an unloaded chunk, bail out of any physics handling
- return;
- }
- if (!g_BlockIsSolid[GotBlock])
- {
- NextPos.x += gCrossCoords[i].x;
- NextPos.z += gCrossCoords[i].z;
- IsNoAirSurrounding = false;
- break;
- }
- } // for i - gCrossCoords[]
-
- if (IsNoAirSurrounding)
+ // The pickup is too close to an unloaded chunk, bail out of any physics handling
+ return;
+ }
+ if (!cBlockInfo::IsSolid(GotBlock))
{
- NextPos.y += 0.5;
+ NextPos.x += gCrossCoords[i].x;
+ NextPos.z += gCrossCoords[i].z;
+ IsNoAirSurrounding = false;
+ break;
}
+ } // for i - gCrossCoords[]
+
+ if (IsNoAirSurrounding)
+ {
+ NextPos.y += 0.5;
+ }
- m_bOnGround = true;
+ m_bOnGround = true;
- /*
- // DEBUG:
- LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
- m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
- );
- */
- }
+ /*
+ // DEBUG:
+ LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
+ m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
+ );
+ */
+ }
- if (!m_bOnGround)
+ if (!m_bOnGround)
+ {
+ float fallspeed;
+ if (IsBlockWater(BlockIn))
{
- float fallspeed;
- if (IsBlockWater(BlockIn))
- {
- fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
- }
- else if (BlockIn == E_BLOCK_COBWEB)
- {
- NextSpeed.y *= 0.05; // Reduce overall falling speed
- fallspeed = 0; // No falling.
- }
- else
- {
- // Normal gravity
- fallspeed = m_Gravity * a_Dt;
- }
- NextSpeed.y += fallspeed;
+ fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
+ }
+ else if (BlockIn == E_BLOCK_COBWEB)
+ {
+ NextSpeed.y *= 0.05; // Reduce overall falling speed
+ fallspeed = 0; // No falling.
}
else
{
- // Friction
- if (NextSpeed.SqrLength() > 0.0004f)
+ // Normal gravity
+ fallspeed = m_Gravity * a_Dt;
+ }
+ NextSpeed.y += fallspeed;
+ }
+ else
+ {
+ // Friction
+ if (NextSpeed.SqrLength() > 0.0004f)
+ {
+ NextSpeed.x *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.x) < 0.05)
{
- NextSpeed.x *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.x) < 0.05)
- {
- NextSpeed.x = 0;
- }
- NextSpeed.z *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.z) < 0.05)
- {
- NextSpeed.z = 0;
- }
+ NextSpeed.x = 0;
+ }
+ NextSpeed.z *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.z) < 0.05)
+ {
+ NextSpeed.z = 0;
}
}
+ }
- // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
- // might have different speed modifiers according to terrain.
- if (BlockIn == E_BLOCK_COBWEB)
- {
- NextSpeed.x *= 0.25;
- NextSpeed.z *= 0.25;
- }
+ // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
+ // might have different speed modifiers according to terrain.
+ if (BlockIn == E_BLOCK_COBWEB)
+ {
+ NextSpeed.x *= 0.25;
+ NextSpeed.z *= 0.25;
+ }
- //Get water direction
- Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
+ //Get water direction
+ Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
- m_WaterSpeed *= 0.9f; //Reduce speed each tick
+ m_WaterSpeed *= 0.9f; //Reduce speed each tick
- switch(WaterDir)
- {
- case X_PLUS:
- m_WaterSpeed.x = 0.2f;
- m_bOnGround = false;
- break;
- case X_MINUS:
- m_WaterSpeed.x = -0.2f;
- m_bOnGround = false;
- break;
- case Z_PLUS:
- m_WaterSpeed.z = 0.2f;
- m_bOnGround = false;
- break;
- case Z_MINUS:
- m_WaterSpeed.z = -0.2f;
- m_bOnGround = false;
- break;
-
- default:
+ switch(WaterDir)
+ {
+ case X_PLUS:
+ m_WaterSpeed.x = 0.2f;
+ m_bOnGround = false;
break;
- }
+ case X_MINUS:
+ m_WaterSpeed.x = -0.2f;
+ m_bOnGround = false;
+ break;
+ case Z_PLUS:
+ m_WaterSpeed.z = 0.2f;
+ m_bOnGround = false;
+ break;
+ case Z_MINUS:
+ m_WaterSpeed.z = -0.2f;
+ m_bOnGround = false;
+ break;
+
+ default:
+ break;
+ }
- if (fabs(m_WaterSpeed.x) < 0.05)
- {
- m_WaterSpeed.x = 0;
- }
+ if (fabs(m_WaterSpeed.x) < 0.05)
+ {
+ m_WaterSpeed.x = 0;
+ }
- if (fabs(m_WaterSpeed.z) < 0.05)
- {
- m_WaterSpeed.z = 0;
- }
+ if (fabs(m_WaterSpeed.z) < 0.05)
+ {
+ m_WaterSpeed.z = 0;
+ }
- NextSpeed += m_WaterSpeed;
+ NextSpeed += m_WaterSpeed;
- if( NextSpeed.SqrLength() > 0.f )
+ if( NextSpeed.SqrLength() > 0.f )
+ {
+ cTracer Tracer( GetWorld() );
+ bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 );
+ if (HasHit) // Oh noez! we hit something
{
- cTracer Tracer( GetWorld() );
- int Ret = Tracer.Trace( NextPos, NextSpeed, 2 );
- if( Ret ) // Oh noez! we hit something
+ // Set to hit position
+ if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength())
{
- // Set to hit position
- if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() )
- {
- if( Ret == 1 )
- {
- if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f;
- if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f;
- if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f;
-
- if( Tracer.HitNormal.y > 0 ) // means on ground
- {
- m_bOnGround = true;
- }
- }
- NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
- NextPos.x += Tracer.HitNormal.x * 0.3f;
- NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot
- NextPos.z += Tracer.HitNormal.z * 0.3f;
- }
- else
+ if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f;
+ if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f;
+ if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f;
+
+ if (Tracer.HitNormal.y > 0) // means on ground
{
- NextPos += (NextSpeed * a_Dt);
+ m_bOnGround = true;
}
+ NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
+ NextPos.x += Tracer.HitNormal.x * 0.3f;
+ NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot
+ NextPos.z += Tracer.HitNormal.z * 0.3f;
}
else
{
- // We didn't hit anything, so move =]
NextPos += (NextSpeed * a_Dt);
}
}
- BlockX = (int) floor(NextPos.x);
- BlockZ = (int) floor(NextPos.z);
- NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ);
- // See if we can commit our changes. If not, we will discard them.
- if (NextChunk != NULL)
+ else
{
- if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
- if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
- if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
- if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
- if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
- if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
+ // We didn't hit anything, so move =]
+ NextPos += (NextSpeed * a_Dt);
}
}
+
+ BlockX = (int) floor(NextPos.x);
+ BlockZ = (int) floor(NextPos.z);
+
+ cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
+ // See if we can commit our changes. If not, we will discard them.
+ if (NextChunk != NULL)
+ {
+ if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
+ if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
+ if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
+ if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
+ if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
+ if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
+ }
}
@@ -815,14 +818,13 @@ void cEntity::TickBurning(cChunk & a_Chunk)
{
int RelX = x;
int RelZ = z;
- cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
- if (CurChunk == NULL)
- {
- continue;
- }
+
for (int y = MinY; y <= MaxY; y++)
{
- switch (CurChunk->GetBlock(RelX, y, RelZ))
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(RelX, y, RelZ, Block);
+
+ switch (Block)
{
case E_BLOCK_FIRE:
{
@@ -922,7 +924,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk)
void cEntity::SetSwimState(cChunk & a_Chunk)
{
- int RelY = (int)floor(m_LastPosY + 0.1);
+ int RelY = (int)floor(GetPosY() + 0.1);
if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
{
m_IsSwimming = false;
@@ -931,11 +933,10 @@ void cEntity::SetSwimState(cChunk & a_Chunk)
}
BLOCKTYPE BlockIn;
- int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
// Check if the player is swimming:
- // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
{
// This sometimes happens on Linux machines
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index b3b1cef83..6e3f8292b 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -2,9 +2,7 @@
#pragma once
#include "../Item.h"
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-#include "../Vector3i.h"
+#include "../Vector3.h"
@@ -71,6 +69,7 @@ public:
enum eEntityType
{
etEntity, // For all other types
+ etEnderCrystal,
etPlayer,
etPickup,
etMonster,
@@ -119,6 +118,7 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage
+ VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage
} ;
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
@@ -131,18 +131,19 @@ public:
eEntityType GetEntityType(void) const { return m_EntityType; }
- bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
- bool IsPickup (void) const { return (m_EntityType == etPickup); }
- bool IsMob (void) const { return (m_EntityType == etMonster); }
+ bool IsEnderCrystal(void) const { return (m_EntityType == etEnderCrystal); }
+ bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
+ bool IsPickup (void) const { return (m_EntityType == etPickup); }
+ bool IsMob (void) const { return (m_EntityType == etMonster); }
bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
- bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
- bool IsBoat (void) const { return (m_EntityType == etBoat); }
- bool IsTNT (void) const { return (m_EntityType == etTNT); }
- bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
- bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
- bool IsFloater (void) const { return (m_EntityType == etFloater); }
- bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
- bool IsPainting (void) const { return (m_EntityType == etPainting); }
+ bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
+ bool IsBoat (void) const { return (m_EntityType == etBoat); }
+ bool IsTNT (void) const { return (m_EntityType == etTNT); }
+ bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
+ bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
+ bool IsFloater (void) const { return (m_EntityType == etFloater); }
+ bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
+ bool IsPainting (void) const { return (m_EntityType == etPainting); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
@@ -158,7 +159,7 @@ public:
cWorld * GetWorld(void) const { return m_World; }
- double GetHeadYaw (void) const { return m_HeadYaw; }
+ double GetHeadYaw (void) const { return m_HeadYaw; } // In degrees
double GetHeight (void) const { return m_Height; }
double GetMass (void) const { return m_Mass; }
const Vector3d & GetPosition (void) const { return m_Pos; }
@@ -166,9 +167,9 @@ public:
double GetPosY (void) const { return m_Pos.y; }
double GetPosZ (void) const { return m_Pos.z; }
const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components
- double GetYaw (void) const { return m_Rot.x; }
- double GetPitch (void) const { return m_Rot.y; }
- double GetRoll (void) const { return m_Rot.z; }
+ double GetYaw (void) const { return m_Rot.x; } // In degrees, [-180, +180)
+ double GetPitch (void) const { return m_Rot.y; } // In degrees, [-180, +180), but normal client clips to [-90, +90]
+ double GetRoll (void) const { return m_Rot.z; } // In degrees, unused in current client
Vector3d GetLookVector(void) const;
const Vector3d & GetSpeed (void) const { return m_Speed; }
double GetSpeedX (void) const { return m_Speed.x; }
@@ -188,9 +189,9 @@ public:
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components
- void SetYaw (double a_Yaw);
- void SetPitch (double a_Pitch);
- void SetRoll (double a_Roll);
+ void SetYaw (double a_Yaw); // In degrees, normalizes to [-180, +180)
+ void SetPitch (double a_Pitch); // In degrees, normalizes to [-180, +180)
+ void SetRoll (double a_Roll); // In degrees, normalizes to [-180, +180)
void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ);
void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); }
void SetSpeedX (double a_SpeedX);
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index 3398f1c7b..3623c869a 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -5,20 +5,26 @@
#include "../ClientHandle.h"
-cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward) :
- cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+ : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
-cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) :
- cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
+ : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
@@ -52,7 +58,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward);
- m_World->BroadcastSoundEffect("random.orb", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
@@ -64,4 +70,10 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
BroadcastMovementUpdate();
}
HandlePhysics(a_Dt, a_Chunk);
+
+ m_Timer += a_Dt;
+ if (m_Timer >= 1000 * 60 * 5) // 5 minutes
+ {
+ Destroy(true);
+ }
}
diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h
index 47d86922c..e76274ac9 100644
--- a/src/Entities/ExpOrb.h
+++ b/src/Entities/ExpOrb.h
@@ -7,14 +7,17 @@
+// tolua_begin
class cExpOrb :
public cEntity
{
typedef cExpOrb super;
public:
+ // tolua_end
+
CLASS_PROTODEF(cExpOrb);
-
+
cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward);
cExpOrb(const Vector3d & a_Pos, int a_Reward);
@@ -22,9 +25,21 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
- // cExpOrb functions
- int GetReward(void) const { return m_Reward; }
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Get the exp amount */
+ int GetReward(void) const { return m_Reward; } // tolua_export
+
+ /** Set the exp amount */
+ void SetReward(int a_Reward) { m_Reward = a_Reward; } // tolua_export
protected:
int m_Reward;
-} ; \ No newline at end of file
+
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
+ float m_Timer;
+} ; // tolua_export
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index 9fcd9ac80..a66c7e4ae 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -33,20 +33,16 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
{
- float MilliDt = a_Dt * 0.001f;
- AddSpeedY(MilliDt * -9.8f);
- AddPosY(GetSpeedY() * MilliDt);
-
// GetWorld()->BroadcastTeleportEntity(*this); // Test position
- int BlockX = m_OriginalPosition.x;
+ int BlockX = POSX_TOINT;
int BlockY = (int)(GetPosY() - 0.5);
- int BlockZ = m_OriginalPosition.z;
+ int BlockZ = POSZ_TOINT;
if (BlockY < 0)
{
// Fallen out of this world, just continue falling until out of sight, then destroy:
- if (BlockY < 100)
+ if (BlockY < VOID_BOUNDARY)
{
Destroy(true);
}
@@ -86,6 +82,15 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
Destroy(true);
return;
}
+
+ float MilliDt = a_Dt * 0.001f;
+ AddSpeedY(MilliDt * -9.8f);
+ AddPosition(GetSpeed() * MilliDt);
+
+ if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
+ {
+ BroadcastMovementUpdate();
+ }
}
diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h
index 865d6dc50..547d503f1 100644
--- a/src/Entities/Floater.h
+++ b/src/Entities/Floater.h
@@ -11,7 +11,7 @@
class cFloater :
public cEntity
{
- typedef cFloater super;
+ typedef cEntity super;
public:
//tolua_end
@@ -43,4 +43,4 @@ protected:
// Entity IDs
int m_PlayerID;
int m_AttachedMobID;
-} ; // tolua_export \ No newline at end of file
+} ; // tolua_export
diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp
new file mode 100644
index 000000000..41ac86268
--- /dev/null
+++ b/src/Entities/HangingEntity.cpp
@@ -0,0 +1,53 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "HangingEntity.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
+ : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
+ , m_BlockFace(a_BlockFace)
+{
+ SetMaxHealth(1);
+ SetHealth(1);
+}
+
+
+
+
+
+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_BlockFace)
+ {
+ 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 to spawn item frame!"); return;
+ }
+
+ 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);
+}
+
+
+
+
diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h
new file mode 100644
index 000000000..6498e4b5b
--- /dev/null
+++ b/src/Entities/HangingEntity.h
@@ -0,0 +1,49 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cHangingEntity :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+
+ CLASS_PROTODEF(cHangingEntity);
+
+ cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
+
+ /** Returns the orientation from the hanging entity */
+ eBlockFace GetDirection() const { return m_BlockFace; } // tolua_export
+
+ /** Set the orientation from the hanging entity */
+ void SetDirection(eBlockFace a_BlockFace) { m_BlockFace = a_BlockFace; } // tolua_export
+
+ /** Returns the X coord. */
+ int GetTileX() const { return POSX_TOINT; } // tolua_export
+
+ /** Returns the Y coord. */
+ int GetTileY() const { return POSY_TOINT; } // tolua_export
+
+ /** Returns the Z coord. */
+ int GetTileZ() const { return POSZ_TOINT; } // tolua_export
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+
+ eBlockFace m_BlockFace;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index 8cfa5e18d..9dd909880 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -10,43 +10,10 @@
cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
- : cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8),
- m_BlockFace(a_BlockFace),
- m_Item(E_BLOCK_AIR),
- m_Rotation(0)
+ : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
+ , m_Item(E_BLOCK_AIR)
+ , m_Rotation(0)
{
- SetMaxHealth(1);
- SetHealth(1);
-}
-
-
-
-
-
-void cItemFrame::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_BlockFace)
- {
- 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 to spawn item frame!"); return;
- }
-
- 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());
}
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
index 43915e3f9..6577e7d94 100644
--- a/src/Entities/ItemFrame.h
+++ b/src/Entities/ItemFrame.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Entity.h"
+#include "HangingEntity.h"
@@ -9,10 +9,10 @@
// tolua_begin
class cItemFrame :
- public cEntity
+ public cHangingEntity
{
// tolua_end
- typedef cEntity super;
+ typedef cHangingEntity super;
public:
@@ -20,18 +20,24 @@ public:
cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
- const cItem & GetItem(void) { return m_Item; }
- Byte GetRotation(void) const { return m_Rotation; }
+ /** Returns the item in the frame */
+ const cItem & GetItem(void) { return m_Item; } // tolua_export
+
+ /** Set the item in the frame */
+ void SetItem(cItem & a_Item) { m_Item = a_Item; }; // tolua_export
+
+ /** Returns the rotation from the item in the frame */
+ Byte GetRotation(void) const { return m_Rotation; } // tolua_export
+
+ /** Set the rotation from the item in the frame */
+ void SetRotation(Byte a_Rotation) { m_Rotation = a_Rotation; } // tolua_export
private:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
virtual void KilledBy(cEntity * a_Killer) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
- eBlockFace m_BlockFace;
cItem m_Item;
Byte m_Rotation;
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index d854906b7..7f38aa35a 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -720,7 +720,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
if (GetSpeedZ() > 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
- if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
@@ -737,7 +737,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
else if (GetSpeedZ() < 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
- if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
@@ -757,7 +757,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
if (GetSpeedX() > 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
- if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
@@ -773,7 +773,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
else if (GetSpeedX() < 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
- if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
@@ -798,10 +798,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
if (
- (!IsBlockRail(BlockXM) && g_BlockIsSolid[BlockXM]) ||
- (!IsBlockRail(BlockXP) && g_BlockIsSolid[BlockXP]) ||
- (!IsBlockRail(BlockZM) && g_BlockIsSolid[BlockZM]) ||
- (!IsBlockRail(BlockZP) && g_BlockIsSolid[BlockZP])
+ (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
+ (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
+ (!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM)) ||
+ (!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP))
)
{
SetSpeed(0, 0, 0);
@@ -1031,9 +1031,9 @@ cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
-void cMinecartWithChest::SetSlot(int a_Idx, const cItem & a_Item)
+void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item)
{
- ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
+ ASSERT(a_Idx < ARRAYCOUNT(m_Items));
m_Items[a_Idx] = a_Item;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 073e78953..ebdb576e0 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -122,7 +122,7 @@ public:
const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; }
cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; }
- void SetSlot(int a_Idx, const cItem & a_Item);
+ void SetSlot(size_t a_Idx, const cItem & a_Item);
protected:
@@ -193,4 +193,4 @@ public:
CLASS_PROTODEF(cMinecartWithHopper);
cMinecartWithHopper(double a_X, double a_Y, double a_Z);
-} ; \ No newline at end of file
+} ;
diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp
index b98c1e67a..e217556c7 100644
--- a/src/Entities/Painting.cpp
+++ b/src/Entities/Painting.cpp
@@ -4,6 +4,7 @@
#include "Painting.h"
#include "ClientHandle.h"
#include "Player.h"
+#include "../Chunk.h"
@@ -30,6 +31,16 @@ void cPainting::SpawnOn(cClientHandle & a_Client)
+void cPainting::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
+}
+
+
+
+
+
void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
{
if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h
index 95afbed1e..c1024bd1b 100644
--- a/src/Entities/Painting.h
+++ b/src/Entities/Painting.h
@@ -24,7 +24,7 @@ public:
private:
virtual void SpawnOn(cClientHandle & a_Client) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void KilledBy(cEntity * a_Killer) override
{
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index c5503c16a..7fc89b62b 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -82,7 +82,7 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
void cPickup::SpawnOn(cClientHandle & a_Client)
{
- a_Client.SendPickupSpawn(*this);
+ a_Client.SendPickupSpawn(*this);
}
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index c273567d1..74b917bce 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -26,31 +26,34 @@ public:
CLASS_PROTODEF(cPickup);
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f);
-
+
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
-
+
bool CollectedBy(cPlayer * a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- /// Returns the number of ticks that this entity has existed
- int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
-
- /// Returns true if the pickup has already been collected
+
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Returns true if the pickup has already been collected */
bool IsCollected(void) const { return m_bCollected; } // tolua_export
- /// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time
+ /** Returns true if created by player (i.e. vomiting), used for determining picking-up delay time */
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
-
+
private:
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
Vector3d m_WaterSpeed;
- /// The number of ticks that the entity has existed / timer between collect and destroy; in msec
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
cItem m_Item;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index e0f0b9222..646aad50f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -10,17 +10,11 @@
#include "../BlockEntities/BlockEntity.h"
#include "../GroupManager.h"
#include "../Group.h"
-#include "../ChatColor.h"
-#include "../Item.h"
-#include "../Tracer.h"
#include "../Root.h"
#include "../OSSupport/Timer.h"
-#include "../MersenneTwister.h"
#include "../Chunk.h"
#include "../Items/ItemHandler.h"
-
-#include "../Vector3d.h"
-#include "../Vector3f.h"
+#include "../Vector3.h"
#include "inifile/iniFile.h"
#include "json/json.h"
@@ -45,15 +39,13 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_Inventory(*this)
, m_CurrentWindow(NULL)
, m_InventoryWindow(NULL)
- , m_TimeLastPickupCheck(0.f)
, m_Color('-')
- , m_LastBlockActionTime(0)
- , m_LastBlockActionCnt(0)
, m_GameMode(eGameMode_NotSet)
, m_IP("")
, m_ClientHandle(a_Client)
- , m_NormalMaxSpeed(0.1)
- , m_SprintingMaxSpeed(0.13)
+ , m_NormalMaxSpeed(1.0)
+ , m_SprintingMaxSpeed(1.3)
+ , m_FlyingMaxSpeed(1.0)
, m_IsCrouched(false)
, m_IsSprinting(false)
, m_IsFlying(false)
@@ -86,7 +78,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastPlayerListTime = t1.GetNowTime();
m_TimeLastTeleportPacket = 0;
- m_TimeLastPickupCheck = 0;
m_PlayerName = a_PlayerName;
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
@@ -694,7 +685,21 @@ const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const
double cPlayer::GetMaxSpeed(void) const
{
- return m_IsSprinting ? m_SprintingMaxSpeed : m_NormalMaxSpeed;
+ if (m_IsFlying)
+ {
+ return m_FlyingMaxSpeed;
+ }
+ else
+ {
+ if (m_IsSprinting)
+ {
+ return m_SprintingMaxSpeed;
+ }
+ else
+ {
+ return m_NormalMaxSpeed;
+ }
+ }
}
@@ -704,7 +709,7 @@ double cPlayer::GetMaxSpeed(void) const
void cPlayer::SetNormalMaxSpeed(double a_Speed)
{
m_NormalMaxSpeed = a_Speed;
- if (!m_IsSprinting)
+ if (!m_IsSprinting && !m_IsFlying)
{
m_ClientHandle->SendPlayerMaxSpeed();
}
@@ -717,7 +722,7 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double a_Speed)
{
m_SprintingMaxSpeed = a_Speed;
- if (m_IsSprinting)
+ if (m_IsSprinting && !m_IsFlying)
{
m_ClientHandle->SendPlayerMaxSpeed();
}
@@ -727,6 +732,18 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed)
+void cPlayer::SetFlyingMaxSpeed(double a_Speed)
+{
+ m_FlyingMaxSpeed = a_Speed;
+
+ // Update the flying speed, always:
+ m_ClientHandle->SendPlayerAbilities();
+}
+
+
+
+
+
void cPlayer::SetCrouch(bool a_IsCrouched)
{
// Set the crouch status, broadcast to all visible players
@@ -858,6 +875,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
else if (a_Killer->IsPlayer())
{
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
+
+ m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1);
}
else
{
@@ -867,24 +886,7 @@ void cPlayer::KilledBy(cEntity * a_Killer)
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
}
- class cIncrementCounterCB
- : public cObjectiveCallback
- {
- AString m_Name;
- public:
- cIncrementCounterCB(const AString & a_Name) : m_Name(a_Name) {}
-
- virtual bool Item(cObjective * a_Objective) override
- {
- a_Objective->AddScore(m_Name, 1);
- return true;
- }
- } IncrementCounter (GetName());
-
- cScoreboard & Scoreboard = m_World->GetScoreBoard();
-
- // Update scoreboard objectives
- Scoreboard.ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter);
+ m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
}
@@ -1062,27 +1064,6 @@ void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
-void cPlayer::SetLastBlockActionTime()
-{
- if (m_World != NULL)
- {
- m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
- }
-}
-
-
-
-
-
-void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
-{
- m_LastBlockActionCnt = a_LastBlockActionCnt;
-}
-
-
-
-
-
void cPlayer::SetGameMode(eGameMode a_GameMode)
{
if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
@@ -1508,6 +1489,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
// Add player to all the necessary parts of the new world
SetWorld(World);
+ m_ClientHandle->StreamChunks();
World->AddEntity(this);
World->AddPlayer(this);
@@ -1529,14 +1511,14 @@ void cPlayer::LoadPermissionsFromDisk()
std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", "");
if (!Groups.empty())
{
- AStringVector Split = StringSplit( Groups, "," );
- for( unsigned int i = 0; i < Split.size(); i++ )
+ AStringVector Split = StringSplitAndTrim(Groups, ",");
+ for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{
- if (!cRoot::Get()->GetGroupManager()->ExistsGroup(Split[i]))
+ if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
{
- LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), m_PlayerName.c_str());
+ LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str());
}
- AddToGroup(Split[i].c_str());
+ AddToGroup(*itr);
}
}
else
@@ -1544,11 +1526,15 @@ void cPlayer::LoadPermissionsFromDisk()
AddToGroup("Default");
}
- m_Color = IniFile.GetValue(m_PlayerName, "Color", "-")[0];
+ AString Color = IniFile.GetValue(m_PlayerName, "Color", "-");
+ if (!Color.empty())
+ {
+ m_Color = Color[0];
+ }
}
else
{
- cRoot::Get()->GetGroupManager()->CheckUsers();
+ cGroupManager::GenerateDefaultUsersIni(IniFile);
AddToGroup("Default");
}
ResolvePermissions();
@@ -1915,7 +1901,7 @@ void cPlayer::Detach()
{
for (int z = PosZ - 2; z <= (PosZ + 2); ++z)
{
- if (!g_BlockIsSolid[m_World->GetBlock(x, y, z)] && g_BlockIsSolid[m_World->GetBlock(x, y - 1, z)])
+ if (!cBlockInfo::IsSolid(m_World->GetBlock(x, y, z)) && cBlockInfo::IsSolid(m_World->GetBlock(x, y - 1, z)))
{
TeleportToCoords(x, y, z);
return;
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index a795bb9eb..ea32dbfb9 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -47,19 +47,19 @@ public:
virtual void HandlePhysics(float a_Dt, cChunk &) override { UNUSED(a_Dt); };
- /// Returns the curently equipped weapon; empty item if none
+ /** Returns the curently equipped weapon; empty item if none */
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
- /// Returns the currently equipped helmet; empty item if nonte
+ /** Returns the currently equipped helmet; empty item if none */
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
- /// Returns the currently equipped chestplate; empty item if none
+ /** Returns the currently equipped chestplate; empty item if none */
virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
- /// Returns the currently equipped leggings; empty item if none
+ /** Returns the currently equipped leggings; empty item if none */
virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
- /// Returns the currently equipped boots; empty item if none
+ /** Returns the currently equipped boots; empty item if none */
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
@@ -77,36 +77,41 @@ public:
*/
short DeltaExperience(short a_Xp_delta);
- /// Gets the experience total - XpTotal for score on death
+ /** Gets the experience total - XpTotal for score on death */
inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; }
- /// Gets the currrent experience
+ /** Gets the currrent experience */
inline short GetCurrentXp(void) { return m_CurrentXp; }
- /// Gets the current level - XpLevel
+ /** Gets the current level - XpLevel */
short GetXpLevel(void);
- /// Gets the experience bar percentage - XpP
+ /** Gets the experience bar percentage - XpP */
float GetXpPercentage(void);
- /// Caculates the amount of XP needed for a given level, ref: http://minecraft.gamepedia.com/XP
+ /** Caculates the amount of XP needed for a given level
+ Ref: http://minecraft.gamepedia.com/XP
+ */
static short XpForLevel(short int a_Level);
- /// inverse of XpForLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations
+ /** Inverse of XpForLevel
+ Ref: http://minecraft.gamepedia.com/XP
+ values are as per this with pre-calculations
+ */
static short CalcLevelFromXp(short int a_CurrentXp);
// tolua_end
- /// Starts charging the equipped bow
+ /** Starts charging the equipped bow */
void StartChargingBow(void);
- /// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged
+ /** Finishes charging the current bow. Returns the number of ticks for which the bow has been charged */
int FinishChargingBow(void);
- /// Cancels the current bow charging
+ /** Cancels the current bow charging */
void CancelChargingBow(void);
- /// Returns true if the player is currently charging the bow
+ /** Returns true if the player is currently charging the bow */
bool IsChargingBow(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround );
@@ -124,16 +129,16 @@ public:
// tolua_begin
- /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment
+ /** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */
Vector3d GetThrowStartPos(void) const;
- /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff.
+ /** Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. */
Vector3d GetThrowSpeed(double a_SpeedCoeff) const;
- /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ /** Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */
eGameMode GetGameMode(void) const { return m_GameMode; }
- /// Returns the current effective gamemode (inherited gamemode is resolved before returning)
+ /** Returns the current effective gamemode (inherited gamemode is resolved before returning) */
eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
/** Sets the gamemode for the player.
@@ -142,56 +147,51 @@ public:
*/
void SetGameMode(eGameMode a_GameMode);
- /// Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world
+ /** Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world */
bool IsGameModeCreative(void) const;
- /// Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world
+ /** Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world */
bool IsGameModeSurvival(void) const;
- /// Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world
+ /** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */
bool IsGameModeAdventure(void) const;
AString GetIP(void) const { return m_IP; } // tolua_export
- /// Returns the associated team, NULL if none
+ /** Returns the associated team, NULL if none */
cTeam * GetTeam(void) { return m_Team; } // tolua_export
- /// Sets the player team, NULL if none
+ /** Sets the player team, NULL if none */
void SetTeam(cTeam * a_Team);
- /// Forces the player to query the scoreboard for his team
+ /** Forces the player to query the scoreboard for his team */
cTeam * UpdateTeam(void);
// tolua_end
void SetIP(const AString & a_IP);
-
- float GetLastBlockActionTime() { return m_LastBlockActionTime; }
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
- void SetLastBlockActionCnt( int );
- void SetLastBlockActionTime();
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
void LoginSetGameMode(eGameMode a_GameMode);
- /// Forces the player to move in the given direction.
+ /** Forces the player to move in the given direction. */
void ForceSetSpeed(Vector3d a_Direction); // tolua_export
- /// Tries to move to a new position, with attachment-related checks (y == -999)
+ /** Tries to move to a new position, with attachment-related checks (y == -999) */
void MoveTo(const Vector3d & a_NewPos); // tolua_export
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
- /// Opens the specified window; closes the current one first using CloseWindow()
+ /** Opens the specified window; closes the current one first using CloseWindow() */
void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
// tolua_begin
- /// Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true
+ /** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */
void CloseWindow(bool a_CanRefuse = true);
- /// Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow
+ /** Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow */
void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true);
cClientHandle * GetClientHandle(void) const { return m_ClientHandle; }
@@ -213,10 +213,10 @@ public:
typedef std::list< cGroup* > GroupList;
typedef std::list< std::string > StringList;
- /// Adds a player to existing group or creates a new group when it doesn't exist
+ /** Adds a player to existing group or creates a new group when it doesn't exist */
void AddToGroup( const AString & a_GroupName ); // tolua_export
- /// Removes a player from the group, resolves permissions and group inheritance (case sensitive)
+ /** Removes a player from the group, resolves permissions and group inheritance (case sensitive) */
void RemoveFromGroup( const AString & a_GroupName ); // tolua_export
bool HasPermission( const AString & a_Permission ); // tolua_export
@@ -239,7 +239,7 @@ public:
/** tosses a pickup newly created from a_Item */
void TossPickup(const cItem & a_Item);
- /// Heals the player by the specified amount of HPs (positive only); sends health update
+ /** Heals the player by the specified amount of HPs (positive only); sends health update */
void Heal(int a_Health);
int GetFoodLevel (void) const { return m_FoodLevel; }
@@ -248,7 +248,7 @@ public:
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
- /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore
+ /** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */
bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
void SetFoodLevel (int a_FoodLevel);
@@ -257,25 +257,28 @@ public:
void SetFoodExhaustionLevel (double a_FoodExhaustionLevel);
void SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining);
- /// Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full"
+ /** Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full" */
bool Feed(int a_Food, double a_Saturation);
- /// Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values.
+ /** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */
void AddFoodExhaustion(double a_Exhaustion)
{
m_FoodExhaustionLevel += a_Exhaustion;
}
- /// Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two
+ /** Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two */
void FoodPoison(int a_NumTicks);
- /// Returns true if the player is currently in the process of eating the currently equipped item
+ /** Returns true if the player is currently in the process of eating the currently equipped item */
bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
- /// Returns true if the player is currently flying.
+ /** Returns true if the player is currently flying. */
bool IsFlying(void) const { return m_IsFlying; }
- /// returns true if the player has thrown out a floater.
+ /** Returns if a player is sleeping in a bed */
+ bool IsInBed(void) const { return m_bIsInBed; }
+
+ /** returns true if the player has thrown out a floater. */
bool IsFishing(void) const { return m_IsFishing; }
void SetIsFishing(bool a_IsFishing, int a_FloaterID = -1) { m_IsFishing = a_IsFishing; m_FloaterID = a_FloaterID; }
@@ -283,14 +286,17 @@ public:
int GetFloaterID(void) const { return m_FloaterID; }
// 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; }
- /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet
+ /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
void StartEating(void);
- /// Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets
+ /** Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets */
void FinishEating(void);
- /// Aborts the current eating operation
+ /** Aborts the current eating operation */
void AbortEating(void);
virtual void KilledBy(cEntity * a_Killer) override;
@@ -319,45 +325,51 @@ public:
cItem & GetDraggingItem(void) {return m_DraggingItem; }
// In UI windows, when inventory-painting:
- /// Clears the list of slots that are being inventory-painted. To be used by cWindow only
+ /** Clears the list of slots that are being inventory-painted. To be used by cWindow only */
void ClearInventoryPaintSlots(void);
- /// Adds a slot to the list for inventory painting. To be used by cWindow only
+ /** Adds a slot to the list for inventory painting. To be used by cWindow only */
void AddInventoryPaintSlot(int a_SlotNum);
- /// Returns the list of slots currently stored for inventory painting. To be used by cWindow only
+ /** Returns the list of slots currently stored for inventory painting. To be used by cWindow only */
const cSlotNums & GetInventoryPaintSlots(void) const;
// tolua_begin
- /// Returns the current maximum speed, as reported in the 1.6.1+ protocol (takes current sprinting state into account)
+ /** Returns the current relative maximum speed (takes current sprinting / flying state into account) */
double GetMaxSpeed(void) const;
- /// Gets the normal maximum speed, as reported in the 1.6.1+ protocol, in the protocol units
+ /** Gets the normal relative maximum speed */
double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; }
- /// Gets the sprinting maximum speed, as reported in the 1.6.1+ protocol, in the protocol units
+ /** Gets the sprinting relative maximum speed */
double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; }
- /// Sets the normal maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed.
+ /** Gets the flying relative maximum speed */
+ double GetFlyingMaxSpeed(void) const { return m_FlyingMaxSpeed; }
+
+ /** Sets the normal relative maximum speed. Sends the update to player, if needed. */
void SetNormalMaxSpeed(double a_Speed);
- /// Sets the sprinting maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed.
+ /** Sets the sprinting relative maximum speed. Sends the update to player, if needed. */
void SetSprintingMaxSpeed(double a_Speed);
- /// Sets the crouch status, broadcasts to all visible players
+ /** Sets the flying relative maximum speed. Sends the update to player, if needed. */
+ void SetFlyingMaxSpeed(double a_Speed);
+
+ /** Sets the crouch status, broadcasts to all visible players */
void SetCrouch(bool a_IsCrouched);
- /// Starts or stops sprinting, sends the max speed update to the client, if needed
+ /** Starts or stops sprinting, sends the max speed update to the client, if needed */
void SetSprint(bool a_IsSprinting);
- /// Flags the player as flying
+ /** Flags the player as flying */
void SetFlying(bool a_IsFlying);
- /// If true the player can fly even when he's not in creative.
+ /** If true the player can fly even when he's not in creative. */
void SetCanFly(bool a_CanFly);
- /// Returns wheter the player can fly or not.
+ /** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; }
// tolua_end
@@ -376,10 +388,10 @@ protected:
GroupList m_ResolvedGroups;
GroupList m_Groups;
- std::string m_PlayerName;
- std::string m_LoadedWorldName;
+ AString m_PlayerName;
+ AString m_LoadedWorldName;
- /// Xp Level stuff
+ /** Xp Level stuff */
enum
{
XP_TO_LEVEL15 = 255,
@@ -390,22 +402,22 @@ protected:
bool m_bVisible;
// Food-related variables:
- /// Represents the food bar, one point equals half a "drumstick"
+ /** Represents the food bar, one point equals half a "drumstick" */
int m_FoodLevel;
- /// "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel
+ /** "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel */
double m_FoodSaturationLevel;
- /// Count-up to the healing or damaging action, based on m_FoodLevel
+ /** Count-up to the healing or damaging action, based on m_FoodLevel */
int m_FoodTickTimer;
- /// A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little
+ /** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */
double m_FoodExhaustionLevel;
- /// Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned
+ /** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */
int m_FoodPoisonedTicksRemaining;
- /// Last position that has been recorded for food-related processing:
+ /** Last position that has been recorded for food-related processing: */
Vector3d m_LastFoodPos;
float m_LastJumpHeight;
@@ -416,16 +428,12 @@ protected:
cWindow * m_CurrentWindow;
cWindow * m_InventoryWindow;
- float m_TimeLastPickupCheck;
-
char m_Color;
- float m_LastBlockActionTime;
- int m_LastBlockActionCnt;
eGameMode m_GameMode;
AString m_IP;
- /// The item being dragged by the cursor while in a UI window
+ /** The item being dragged by the cursor while in a UI window */
cItem m_DraggingItem;
long long m_LastPlayerListTime;
@@ -435,12 +443,21 @@ protected:
cSlotNums m_InventoryPaintSlots;
- /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is walking. 0.1 by default
+ /** Max speed, relative to the game default.
+ 1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
+ Default value is 1. */
double m_NormalMaxSpeed;
- /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is sprinting. 0.13 by default
+ /** Max speed, relative to the game default max speed, when sprinting.
+ 1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
+ Default value is 1.3. */
double m_SprintingMaxSpeed;
+ /** Max speed, relative to the game default flying max speed, when flying.
+ 1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
+ Default value is 1. */
+ double m_FlyingMaxSpeed;
+
bool m_IsCrouched;
bool m_IsSprinting;
bool m_IsFlying;
@@ -450,10 +467,10 @@ protected:
bool m_CanFly; // If this is true the player can fly. Even if he is not in creative.
- /// The world tick in which eating will be finished. -1 if not eating
+ /** The world tick in which eating will be finished. -1 if not eating */
Int64 m_EatingFinishTick;
- /// Player Xp level
+ /** Player Xp level */
short int m_LifetimeTotalXp;
short int m_CurrentXp;
@@ -465,7 +482,7 @@ protected:
int m_FloaterID;
- cTeam* m_Team;
+ cTeam * m_Team;
@@ -474,20 +491,25 @@ protected:
virtual void Destroyed(void);
- /// Filters out damage for creative mode/friendly fire
+ /** Filters out damage for creative mode/friendly fire */
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
/** Stops players from burning in creative mode */
virtual void TickBurning(cChunk & a_Chunk) override;
- /// Called in each tick to handle food-related processing
+ /** Called in each tick to handle food-related processing */
void HandleFood(void);
- /// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item.
+ /** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */
void HandleFloater(void);
- /// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
+ /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */
void ApplyFoodExhaustionFromMovement();
+
+ /** Flag representing whether the player is currently in a bed
+ Set by a right click on unoccupied bed, unset by a time fast forward or teleport */
+ bool m_bIsInBed;
+
} ; // tolua_export
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index ef82c6e94..a9735a53c 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -4,6 +4,7 @@
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h"
+#include "../Bindings/PluginManager.h"
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
@@ -50,12 +51,12 @@ protected:
LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)",
a_BlockType, a_BlockMeta,
a_BlockX, a_BlockY, a_BlockZ, a_EntryFace,
- g_BlockIsSolid[a_BlockType] ? "solid" : "non-solid",
+ cBlockInfo::IsSolid(a_BlockType) ? "solid" : "non-solid",
ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str()
);
*/
- if (g_BlockIsSolid[a_BlockType])
+ if (cBlockInfo::IsSolid(a_BlockType))
{
// The projectile hit a solid block
// Calculate the exact hit coords:
@@ -66,6 +67,11 @@ protected:
eBlockFace Face;
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
{
+ if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile))
+ {
+ return false;
+ }
+
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
m_Projectile->OnHitSolidBlock(Intersection, Face);
return true;
@@ -147,7 +153,11 @@ public:
}
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
- // TODO: Allow plugins to interfere about which entities can be hit
+ if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
+ {
+ // A plugin disagreed.
+ return false;
+ }
if (LineCoeff < m_MinCoeff)
{
@@ -214,7 +224,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
-cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
+cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
{
Vector3d Speed;
if (a_Speed != NULL)
@@ -231,8 +241,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
- case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z );
- // TODO: the rest
+ case pkFirework:
+ {
+ if (a_Item.m_FireworkItem.m_Colours.empty())
+ {
+ return NULL;
+ }
+
+ return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
+ }
}
LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
@@ -276,6 +293,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
case pkExpBottle: return "ThrownExpBottle";
case pkSplashPotion: return "ThrownPotion";
case pkWitherSkull: return "WitherSkull";
+ case pkFirework: return "Firework";
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
}
ASSERT(!"Unhandled projectile entity kind!");
@@ -655,8 +673,6 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
- // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
-
Destroy();
}
@@ -664,6 +680,30 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFac
+void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ if (a_EntityHit.IsMob())
+ {
+ cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
+ if (MobType == cMonster::mtBlaze)
+ {
+ TotalDamage = 3;
+ }
+ else if (MobType == cMonster::mtEnderDragon)
+ {
+ TotalDamage = 1;
+ }
+ }
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBottleOEnchantingEntity :
@@ -693,8 +733,10 @@ void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFireworkEntity :
-cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) :
-super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
+super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
+ m_ExplodeTimer(0),
+ m_FireworkItem(a_Item)
{
}
@@ -702,30 +744,20 @@ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
- if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE))
+ int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int PosY = POSY_TOINT;
+
+ if ((PosY < 0) || (PosY >= cChunkDef::Height))
{
- return;
+ goto setspeed;
}
- SetSpeed(0, 0, 0);
- SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
-
- m_IsInGround = true;
-
- BroadcastMovementUpdate();
-}
-
-
-
-
-
-void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
if (m_IsInGround)
{
- if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR)
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
{
m_IsInGround = false;
}
@@ -734,28 +766,35 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return;
}
}
+ else
+ {
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
+ {
+ OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
+ return;
+ }
+ }
- Vector3d PerTickSpeed = GetSpeed() / 20;
- Vector3d Pos = GetPosition();
+setspeed:
+ AddSpeedY(1);
+ AddPosition(GetSpeed() * (a_Dt / 1000));
+}
- // Trace the tick's worth of movement as a line:
- Vector3d NextPos = Pos + PerTickSpeed;
- cProjectileTracerCallback TracerCallback(this);
- if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
+
+
+
+
+void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{
- // Something has been hit, abort all other processing
- return;
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
+ Destroy();
}
- // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
-
- // Update the position:
- SetPosition(NextPos);
- // Add slowdown and gravity effect to the speed:
- Vector3d NewSpeed(GetSpeed());
- NewSpeed.y += 2;
- NewSpeed *= TracerCallback.GetSlowdownCoeff();
- SetSpeed(NewSpeed);
+ m_ExplodeTimer++;
}
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index e80592999..efb7ae783 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -46,7 +46,7 @@ public:
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
- static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
+ static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
@@ -259,6 +259,7 @@ protected:
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// tolua_begin
@@ -305,13 +306,19 @@ public:
CLASS_PROTODEF(cFireworkEntity);
- cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z);
+ cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
+ const cItem & GetItem(void) const { return m_FireworkItem; }
protected:
// cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ int m_ExplodeTimer;
+ cItem m_FireworkItem;
// tolua_begin
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index 339107b2e..02f31f5bb 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -8,10 +8,9 @@
-cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks) :
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -19,10 +18,9 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSe
-cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -42,18 +40,27 @@ void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
+void cTNTEntity::Explode(void)
+{
+ m_FuseTicks = 0;
+ Destroy(true);
+ LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
+ m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
+}
+
+
+
+
+
void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
- float delta_time = a_Dt / 1000; // Convert miliseconds to seconds
- m_Counter += delta_time;
- if (m_Counter > m_MaxFuseTime) // Check if we go KABOOOM
+
+ m_FuseTicks -= 1;
+ if (m_FuseTicks <= 0)
{
- Destroy(true);
- LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
- m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
- return;
+ Explode();
}
}
diff --git a/src/Entities/TNTEntity.h b/src/Entities/TNTEntity.h
index d1fcae766..116f5a8cb 100644
--- a/src/Entities/TNTEntity.h
+++ b/src/Entities/TNTEntity.h
@@ -16,19 +16,28 @@ public:
// tolua_end
CLASS_PROTODEF(cTNTEntity);
- cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec);
- cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
+ cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks = 80);
+ cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks = 80);
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- double GetCounterTime(void) const { return m_Counter; } // tolua_export
- double GetMaxFuseTime(void) const { return m_MaxFuseTime; } // tolua_export
+
+ // tolua_begin
+
+ /** Explode the tnt */
+ void Explode(void);
+
+ /** Returns the fuse ticks until the tnt will explode */
+ int GetFuseTicks(void) const { return m_FuseTicks; }
+
+ /** Set the fuse ticks until the tnt will explode */
+ void SetFuseTicks(int a_FuseTicks) { m_FuseTicks = a_FuseTicks; }
+
+ // tolua_end
protected:
- double m_Counter; ///< How much time has elapsed since the object was created, in seconds
- double m_MaxFuseTime; ///< How long the fuse is, in seconds
+ int m_FuseTicks; ///< How much ticks is left, while the tnt will explode
}; // tolua_export
diff --git a/src/ForEachChunkProvider.h b/src/ForEachChunkProvider.h
index 6017173ee..7a6e8c5c6 100644
--- a/src/ForEachChunkProvider.h
+++ b/src/ForEachChunkProvider.h
@@ -24,6 +24,8 @@ class cBlockArea;
class cForEachChunkProvider
{
public:
+ virtual ~cForEachChunkProvider() {}
+
/** Calls the callback for each chunk in the specified range. */
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) = 0;
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 2e2276981..1810d7c49 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -175,7 +175,7 @@ void cFurnaceRecipe::ReloadRecipes(void)
{
LOGERROR("ERROR: FurnaceRecipe, syntax error" );
}
- LOG("Loaded %u furnace recipes and %u fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
+ LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
}
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 967deba6a..32a687201 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -371,8 +371,8 @@ void cBioGenDistortedVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::B
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
for (int z = 0; z < cChunkDef::Width; z++)
{
@@ -477,8 +477,8 @@ void cBioGenMultiStepMap::DecideOceanLandMushroom(int a_ChunkX, int a_ChunkZ, cC
{
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Prepare a 9x9 area of neighboring cell seeds
// (assuming that 7x7 cell area is larger than a chunk being generated)
@@ -651,8 +651,8 @@ void cBioGenMultiStepMap::BuildTemperatureHumidityMaps(int a_ChunkX, int a_Chunk
HumidityMap[x + 17 * z] = NoiseH;
} // for x
} // for z
- LinearUpscale2DArrayInPlace(TemperatureMap, 17, 17, 8, 8);
- LinearUpscale2DArrayInPlace(HumidityMap, 17, 17, 8, 8);
+ LinearUpscale2DArrayInPlace<17, 17, 8, 8>(TemperatureMap);
+ LinearUpscale2DArrayInPlace<17, 17, 8, 8>(HumidityMap);
// Re-map into integral values in [0 .. 255] range:
for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++)
@@ -778,8 +778,8 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that:
for (int z = 0; z < cChunkDef::Width; z++)
diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp
index 2571e6b77..98b7c8681 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -762,7 +762,7 @@ void cStructGenWormNestCaves::ClearCache(void)
-void cStructGenWormNestCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -902,7 +902,7 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
-void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenMarbleCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
cNoise Noise(m_Seed);
for (int z = 0; z < cChunkDef::Width; z++)
@@ -938,7 +938,7 @@ void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenDualRidgeCaves:
-void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDualRidgeCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
diff --git a/src/Generating/Caves.h b/src/Generating/Caves.h
index ea7f10bf4..7c45c056b 100644
--- a/src/Generating/Caves.h
+++ b/src/Generating/Caves.h
@@ -20,7 +20,7 @@
class cStructGenMarbleCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenMarbleCaves(int a_Seed) : m_Seed(a_Seed) {}
@@ -29,8 +29,8 @@ protected:
int m_Seed;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -38,7 +38,7 @@ protected:
class cStructGenDualRidgeCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDualRidgeCaves(int a_Seed, float a_Threshold) :
@@ -55,8 +55,8 @@ protected:
int m_Seed;
float m_Threshold;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -64,7 +64,7 @@ protected:
class cStructGenWormNestCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) :
@@ -94,7 +94,7 @@ protected:
void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves);
// cStructGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index d9529b4b0..7711723fc 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -209,6 +209,7 @@ bool cChunkDesc::IsUsingDefaultComposition(void) const
void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
{
+ LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
m_bUseDefaultStructures = a_bUseDefaultStructures;
}
@@ -218,6 +219,7 @@ void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
bool cChunkDesc::IsUsingDefaultStructures(void) const
{
+ LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
return m_bUseDefaultStructures;
}
@@ -341,9 +343,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
- a_Dest.m_OriginY = a_MinRelY;
- a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.y = a_MinRelY;
+ a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index ef38f1399..73f0223e8 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -116,7 +116,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk
// Add to queue, issue a warning if too many:
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
{
- LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
+ LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
}
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
}
@@ -180,7 +180,7 @@ BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_S
BLOCKTYPE Block = BlockStringToType(BlockType);
if (Block < 0)
{
- LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
+ LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
return BlockStringToType(a_Default);
}
return Block;
diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp
index 60356fe46..578bb2481 100644
--- a/src/Generating/CompoGen.cpp
+++ b/src/Generating/CompoGen.cpp
@@ -566,7 +566,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments:
for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@@ -579,7 +579,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index cfa7e9c6f..2e886336f 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -21,7 +21,9 @@
#include "DistortedHeightmap.h"
#include "EndGen.h"
#include "MineShafts.h"
+#include "NetherFortGen.h"
#include "Noise3DGenerator.h"
+#include "POCPieceGenerator.h"
#include "Ravines.h"
@@ -133,11 +135,6 @@ cComposableGenerator::~cComposableGenerator()
delete *itr;
}
m_FinishGens.clear();
- for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
- {
- delete *itr;
- }
- m_StructureGens.clear();
delete m_CompositionGen;
m_CompositionGen = NULL;
@@ -164,7 +161,6 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
InitBiomeGen(a_IniFile);
InitHeightGen(a_IniFile);
InitCompositionGen(a_IniFile);
- InitStructureGens(a_IniFile);
InitFinishGens(a_IniFile);
}
@@ -196,25 +192,25 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
}
+ bool ShouldUpdateHeightmap = false;
if (a_ChunkDesc.IsUsingDefaultComposition())
{
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
+ ShouldUpdateHeightmap = true;
}
- if (a_ChunkDesc.IsUsingDefaultStructures())
- {
- for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
- {
- (*itr)->GenStructures(a_ChunkDesc);
- } // for itr - m_StructureGens[]
- }
-
if (a_ChunkDesc.IsUsingDefaultFinish())
{
for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
{
(*itr)->GenFinish(a_ChunkDesc);
} // for itr - m_FinishGens[]
+ ShouldUpdateHeightmap = true;
+ }
+
+ if (ShouldUpdateHeightmap)
+ {
+ a_ChunkDesc.UpdateHeightmap();
}
}
@@ -290,35 +286,69 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
-void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
+void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
- AString Structures = a_IniFile.GetValueSet("Generator", "Structures", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees");
-
int Seed = m_ChunkGenerator.GetSeed();
- AStringVector Str = StringSplitAndTrim(Structures, ",");
+ eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
+
+ // Older configuration used "Structures" in addition to "Finishers"; we don't distinguish between the two anymore (#398)
+ // Therefore, we load Structures from the ini file for compatibility, but move its contents over to Finishers:
+ AString Structures = a_IniFile.GetValue("Generator", "Structures", "");
+ AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
+ if (!Structures.empty())
+ {
+ LOGINFO("[Generator].Structures is deprecated, moving the contents to [Generator].Finishers.");
+ // Structures used to generate before Finishers, so place them first:
+ Structures.append(", ");
+ Finishers = Structures + Finishers;
+ a_IniFile.SetValue("Generator", "Finishers", Finishers);
+ }
+ a_IniFile.DeleteValue("Generator", "Structures");
+
+ // Create all requested finishers:
+ AStringVector Str = StringSplitAndTrim(Finishers, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
- if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
+ // Finishers, alpha-sorted:
+ if (NoCaseCompare(*itr, "BottomLava") == 0)
{
- float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
- m_StructureGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
+ int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
+ m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ }
+ else if (NoCaseCompare(*itr, "DeadBushes") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND));
}
else if (NoCaseCompare(*itr, "DirectOverhangs") == 0)
{
- m_StructureGens.push_back(new cStructGenDirectOverhangs(Seed));
+ m_FinishGens.push_back(new cStructGenDirectOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0)
{
- m_StructureGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
+ m_FinishGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
+ }
+ else if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
+ {
+ float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
+ m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ }
+ else if (NoCaseCompare(*itr, "Ice") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenIce);
}
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
- m_StructureGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
+ m_FinishGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
+ }
+ else if (NoCaseCompare(*itr, "LavaSprings") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
}
else if (NoCaseCompare(*itr, "MarbleCaves") == 0)
{
- m_StructureGens.push_back(new cStructGenMarbleCaves(Seed));
+ m_FinishGens.push_back(new cStructGenMarbleCaves(Seed));
}
else if (NoCaseCompare(*itr, "MineShafts") == 0)
{
@@ -327,94 +357,69 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
- m_StructureGens.push_back(new cStructGenMineShafts(
- Seed, GridSize, MaxSystemSize,
+ m_FinishGens.push_back(new cStructGenMineShafts(
+ Seed, GridSize, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
));
}
- else if (NoCaseCompare(*itr, "OreNests") == 0)
- {
- m_StructureGens.push_back(new cStructGenOreNests(Seed));
- }
- else if (NoCaseCompare(*itr, "Ravines") == 0)
- {
- m_StructureGens.push_back(new cStructGenRavines(Seed, 128));
- }
- else if (NoCaseCompare(*itr, "Trees") == 0)
+ else if (NoCaseCompare(*itr, "Lilypads") == 0)
{
- m_StructureGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
+ m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
}
- else if (NoCaseCompare(*itr, "WaterLakes") == 0)
+ else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
{
- int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
- m_StructureGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
+ m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
}
- else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
+ else if (NoCaseCompare(*itr, "NetherForts") == 0)
{
- m_StructureGens.push_back(new cStructGenWormNestCaves(Seed));
+ int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512);
+ int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12);
+ m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxDepth));
}
- else
+ else if (NoCaseCompare(*itr, "OreNests") == 0)
{
- LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str());
+ m_FinishGens.push_back(new cStructGenOreNests(Seed));
}
- } // for itr - Str[]
-}
-
-
-
-
-
-void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
-{
- int Seed = m_ChunkGenerator.GetSeed();
- eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
-
- AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
- AStringVector Str = StringSplitAndTrim(Finishers, ",");
- for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
- {
- // Finishers, alpha-sorted:
- if (NoCaseCompare(*itr, "BottomLava") == 0)
+ else if (NoCaseCompare(*itr, "POCPieces") == 0)
{
- int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
- int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
- m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
}
- else if (NoCaseCompare(*itr, "DeadBushes") == 0)
+ else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
- m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND));
+ m_FinishGens.push_back(new cFinishGenPreSimulator);
}
- else if (NoCaseCompare(*itr, "Ice") == 0)
+ else if (NoCaseCompare(*itr, "Ravines") == 0)
{
- m_FinishGens.push_back(new cFinishGenIce);
+ m_FinishGens.push_back(new cStructGenRavines(Seed, 128));
}
- else if (NoCaseCompare(*itr, "LavaSprings") == 0)
+ else if (NoCaseCompare(*itr, "Snow") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
+ m_FinishGens.push_back(new cFinishGenSnow);
}
- else if (NoCaseCompare(*itr, "Lilypads") == 0)
+ else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
{
- m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
+ m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
}
- else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
+ else if (NoCaseCompare(*itr, "Trees") == 0)
{
- m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
+ m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
}
- else if (NoCaseCompare(*itr, "PreSimulator") == 0)
+ else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
- m_FinishGens.push_back(new cFinishGenPreSimulator);
+ int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
+ m_FinishGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
}
- else if (NoCaseCompare(*itr, "Snow") == 0)
+ else if (NoCaseCompare(*itr, "WaterSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenSnow);
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
}
- else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
+ else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
{
- m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
+ m_FinishGens.push_back(new cStructGenWormNestCaves(Seed));
}
- else if (NoCaseCompare(*itr, "WaterSprings") == 0)
+ else
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
+ LOGWARNING("Unknown Finisher in the [Generator] section: \"%s\". Ignoring.", itr->c_str());
}
} // for itr - Str[]
}
diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h
index 29add0636..6b7627d2e 100644
--- a/src/Generating/ComposableGenerator.h
+++ b/src/Generating/ComposableGenerator.h
@@ -43,16 +43,16 @@ class cBiomeGen
public:
virtual ~cBiomeGen() {} // Force a virtual destructor in descendants
- /// Generates biomes for the given chunk
+ /** Generates biomes for the given chunk */
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
- /// Reads parameters from the ini file, prepares generator for use.
+ /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeBiomeGen(cIniFile & a_IniFile) {}
- /// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
- /// a_CacheOffByDefault gets set to whether the cache should be disabled by default
- /// Used in BiomeVisualiser, too.
- /// Implemented in BioGen.cpp!
+ /** Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
+ a_CacheOffByDefault gets set to whether the cache should be disabled by default.
+ Used in BiomeVisualiser, too.
+ Implemented in BioGen.cpp! */
static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
} ;
@@ -72,10 +72,10 @@ class cTerrainHeightGen
public:
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
- /// Generates heightmap for the given chunk
+ /** Generates heightmap for the given chunk */
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
- /// Reads parameters from the ini file, prepares generator for use.
+ /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
@@ -102,7 +102,7 @@ public:
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
- /// Reads parameters from the ini file, prepares generator for use.
+ /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
@@ -116,28 +116,12 @@ public:
-/** The interface that a structure generator must implement
-Structures are generated after the terrain composition took place. It should modify the blocktype data to account
-for whatever structures the generator is generating.
-Note that ores are considered structures too, at least from the interface point of view.
-Also note that a worldgenerator may contain multiple structure generators, one for each type of structure
-*/
-class cStructureGen
-{
-public:
- virtual ~cStructureGen() {} // Force a virtual destructor in descendants
-
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) = 0;
-} ;
-
-typedef std::list<cStructureGen *> cStructureGenList;
-
-
-
-
-
/** The interface that a finisher must implement
-Finisher implements small additions after all structures have been generated.
+Finisher implements changes to the chunk after the rough terrain has been generated.
+Examples of finishers are trees, snow, ore, lilypads and others.
+Note that a worldgenerator may contain multiple finishers.
+Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
+no longer relevant, all structure generators are considered finishers now (#398)
*/
class cFinishGen
{
@@ -171,7 +155,6 @@ protected:
cBiomeGen * m_BiomeGen;
cTerrainHeightGen * m_HeightGen;
cTerrainCompositionGen * m_CompositionGen;
- cStructureGenList m_StructureGens;
cFinishGenList m_FinishGens;
// Generators underlying the caches:
@@ -180,19 +163,16 @@ protected:
cTerrainCompositionGen * m_UnderlyingCompositionGen;
- /// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly
+ /** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
void InitBiomeGen(cIniFile & a_IniFile);
- /// Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly
+ /** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
void InitHeightGen(cIniFile & a_IniFile);
- /// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly
+ /** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
void InitCompositionGen(cIniFile & a_IniFile);
- /// Reads the structures to generate from the ini and initializes m_StructureGens accordingly
- void InitStructureGens(cIniFile & a_IniFile);
-
- /// Reads the finishers from the ini and initializes m_FinishGens accordingly
+ /** Reads the finishers from the ini and initializes m_FinishGens accordingly */
void InitFinishGens(cIniFile & a_IniFile);
} ;
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 02045f76a..f2d66af70 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -88,7 +88,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{
continue;
}
- if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks
+ if (!cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ))) // Only place on solid blocks
{
continue;
}
@@ -131,7 +131,7 @@ void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a
}
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z);
- if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks
+ if (!cBlockInfo::IsSolid(BlockBelow)) // Only place on solid blocks
{
continue;
}
@@ -329,7 +329,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
case biFrozenOcean:
{
int Height = a_ChunkDesc.GetHeight(x, z);
- if (g_BlockIsSnowable[a_ChunkDesc.GetBlockType(x, Height, z)])
+ if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
{
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
a_ChunkDesc.SetHeight(x, z, Height + 1);
diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp
index 10710b4a1..3621421c2 100644
--- a/src/Generating/HeiGen.cpp
+++ b/src/Generating/HeiGen.cpp
@@ -428,7 +428,7 @@ void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMa
Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes);
}
}
- LinearUpscale2DArrayInPlace(Height, 17, 17, STEPX, STEPZ);
+ LinearUpscale2DArrayInPlace<17, 17, STEPX, STEPZ>(Height);
// Copy into the heightmap
for (int z = 0; z < cChunkDef::Width; z++)
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index cc39cef7b..231295c3f 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -69,6 +69,8 @@ public:
m_BoundingBox(a_BoundingBox)
{
}
+
+ virtual ~cMineShaft() {}
/// Returns true if this mineshaft intersects the specified cuboid
bool DoesIntersect(const cCuboid & a_Other)
@@ -1338,7 +1340,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
- // Walk the cache, move each cave system that we want into a_Caves:
+ // Walk the cache, move each cave system that we want into a_Mineshafts:
int StartX = BaseX * m_GridSize;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
int StartZ = BaseZ * m_GridSize;
@@ -1407,7 +1409,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
-void cStructGenMineShafts::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h
index c53d3bc53..ba32e75ad 100644
--- a/src/Generating/MineShafts.h
+++ b/src/Generating/MineShafts.h
@@ -17,7 +17,7 @@
class cStructGenMineShafts :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenMineShafts(
@@ -52,8 +52,8 @@ protected:
*/
void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems);
- // cStructureGen overrides:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp
new file mode 100644
index 000000000..02779a8a3
--- /dev/null
+++ b/src/Generating/NetherFortGen.cpp
@@ -0,0 +1,275 @@
+
+// NetherFortGen.cpp
+
+// Implements the cNetherFortGen class representing the nether fortress generator
+
+#include "Globals.h"
+#include "NetherFortGen.h"
+#include "Prefabs/NetherFortPrefabs.h"
+
+
+
+
+
+static const int NEIGHBORHOOD_SIZE = 3;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen::cNetherFort:
+
+class cNetherFortGen::cNetherFort
+{
+public:
+ cNetherFortGen & m_ParentGen;
+ int m_BlockX, m_BlockZ;
+ int m_GridSize;
+ int m_Seed;
+ cPlacedPieces m_Pieces;
+
+
+ cNetherFort(cNetherFortGen & a_ParentGen, int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
+ m_ParentGen(a_ParentGen),
+ m_BlockX(a_BlockX),
+ m_BlockZ(a_BlockZ),
+ m_GridSize(a_GridSize),
+ m_Seed(a_Seed)
+ {
+ // TODO: Proper Y-coord placement
+ int BlockY = 64;
+
+ // Generate pieces:
+ for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++)
+ {
+ cBFSPieceGenerator pg(m_ParentGen, a_Seed + i);
+ pg.PlacePieces(a_BlockX, BlockY, a_BlockZ, a_MaxDepth, m_Pieces);
+ }
+ }
+
+
+ ~cNetherFort()
+ {
+ cPieceGenerator::FreePieces(m_Pieces);
+ }
+
+
+ /** Carves the system into the chunk data */
+ void ProcessChunk(cChunkDesc & a_Chunk)
+ {
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece());
+ Prefab.Draw(a_Chunk, *itr);
+ } // for itr - m_PlacedPieces[]
+ }
+};
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen:
+
+cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) :
+ m_Seed(a_Seed),
+ m_Noise(a_Seed),
+ m_GridSize(a_GridSize),
+ m_MaxDepth(a_MaxDepth)
+{
+ // Initialize the prefabs:
+ for (size_t i = 0; i < g_NetherFortPrefabs1Count; i++)
+ {
+ cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs1[i]);
+ m_AllPieces.push_back(Prefab);
+ if (Prefab->HasConnectorType(0))
+ {
+ m_OuterPieces.push_back(Prefab);
+ }
+ if (Prefab->HasConnectorType(1))
+ {
+ m_InnerPieces.push_back(Prefab);
+ }
+ }
+
+ // Initialize the starting piece prefabs:
+ for (size_t i = 0; i < g_NetherFortStartingPrefabs1Count; i++)
+ {
+ m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs1[i]));
+ }
+
+ // DEBUG: Try one round of placement:
+ cPlacedPieces Pieces;
+ cBFSPieceGenerator pg(*this, a_Seed);
+ pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces);
+}
+
+
+
+
+
+cNetherFortGen::~cNetherFortGen()
+{
+ ClearCache();
+ for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - m_AllPieces[]
+ m_AllPieces.clear();
+}
+
+
+
+
+
+void cNetherFortGen::ClearCache(void)
+{
+ // TODO
+}
+
+
+
+
+
+void cNetherFortGen::GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts)
+{
+ int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
+ int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
+ if (BaseX < 0)
+ {
+ --BaseX;
+ }
+ if (BaseZ < 0)
+ {
+ --BaseZ;
+ }
+ BaseX -= NEIGHBORHOOD_SIZE / 2;
+ BaseZ -= NEIGHBORHOOD_SIZE / 2;
+
+ // Walk the cache, move each cave system that we want into a_Forts:
+ int StartX = BaseX * m_GridSize;
+ int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ int StartZ = BaseZ * m_GridSize;
+ int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ for (cNetherForts::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
+ {
+ if (
+ ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
+ ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
+ )
+ {
+ // want
+ a_Forts.push_back(*itr);
+ itr = m_Cache.erase(itr);
+ }
+ else
+ {
+ // don't want
+ ++itr;
+ }
+ } // for itr - m_Cache[]
+
+ // Create those forts that haven't been in the cache:
+ for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
+ {
+ int RealX = (BaseX + x) * m_GridSize;
+ for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
+ {
+ int RealZ = (BaseZ + z) * m_GridSize;
+ bool Found = false;
+ for (cNetherForts::const_iterator itr = a_Forts.begin(), end = a_Forts.end(); itr != end; ++itr)
+ {
+ if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
+ {
+ Found = true;
+ break;
+ }
+ } // for itr - a_Mineshafts
+ if (!Found)
+ {
+ a_Forts.push_back(new cNetherFort(*this, RealX, RealZ, m_GridSize, m_MaxDepth, m_Seed));
+ }
+ } // for z
+ } // for x
+
+ // Copy a_Forts into m_Cache to the beginning:
+ cNetherForts FortsCopy (a_Forts);
+ m_Cache.splice(m_Cache.begin(), FortsCopy, FortsCopy.begin(), FortsCopy.end());
+
+ // Trim the cache if it's too long:
+ if (m_Cache.size() > 100)
+ {
+ cNetherForts::iterator itr = m_Cache.begin();
+ std::advance(itr, 100);
+ for (cNetherForts::iterator end = m_Cache.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ itr = m_Cache.begin();
+ std::advance(itr, 100);
+ m_Cache.erase(itr, m_Cache.end());
+ }
+}
+
+
+
+
+
+void cNetherFortGen::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cNetherForts Forts;
+ GetFortsForChunk(ChunkX, ChunkZ, Forts);
+ for (cNetherForts::const_iterator itr = Forts.begin(); itr != Forts.end(); ++itr)
+ {
+ (*itr)->ProcessChunk(a_ChunkDesc);
+ } // for itr - Forts[]
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetPiecesWithConnector(int a_ConnectorType)
+{
+ switch (a_ConnectorType)
+ {
+ case 0: return m_OuterPieces;
+ case 1: return m_InnerPieces;
+ default: return cPieces();
+ }
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetStartingPieces(void)
+{
+ return m_StartingPieces;
+}
+
+
+
+
+
+void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cNetherFortGen::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h
new file mode 100644
index 000000000..10ba01396
--- /dev/null
+++ b/src/Generating/NetherFortGen.h
@@ -0,0 +1,86 @@
+
+// NetherFortGen.h
+
+// Declares the cNetherFortGen class representing the nether fortress generator
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+class cNetherFortGen :
+ public cFinishGen,
+ public cPiecePool
+{
+public:
+ cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth);
+
+ virtual ~cNetherFortGen();
+
+protected:
+ class cNetherFort; // fwd: NetherFortGen.cpp
+ typedef std::list<cNetherFort *> cNetherForts;
+
+
+ /** The seed used for generating*/
+ int m_Seed;
+
+ /** The noise used for generating */
+ cNoise m_Noise;
+
+ /** Average spacing between the fortresses*/
+ int m_GridSize;
+
+ /** Maximum depth of the piece-generator tree */
+ int m_MaxDepth;
+
+ /** Cache of the most recently used systems. MoveToFront used. */
+ cNetherForts m_Cache;
+
+ /** All the pieces that are allowed for building.
+ This is the list that's used for memory allocation and deallocation for the pieces. */
+ cPieces m_AllPieces;
+
+ /** The pieces that are used as starting pieces.
+ This list is not shared and the pieces need deallocation. */
+ cPieces m_StartingPieces;
+
+ /** The pieces that have an "outer" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_OuterPieces;
+
+ /** The pieces that have an "inner" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_InnerPieces;
+
+
+ /** Clears everything from the cache.
+ Also invalidates the forst returned by GetFortsForChunk(). */
+ void ClearCache(void);
+
+ /** Returns all forts that *may* intersect the given chunk.
+ The returned forts live within m_Cache.They are valid until the next call
+ to this function (which may delete some of the pointers). */
+ void GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts);
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index afa40c647..15a588d45 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -420,7 +420,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
}
}
// Linear-interpolate this XZ floor:
- LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z);
+ LinearUpscale2DArrayInPlace<17, 17, UPSCALE_X, UPSCALE_Z>(CurFloor);
}
// Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis
diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp
new file mode 100644
index 000000000..9ed4b565e
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.cpp
@@ -0,0 +1,270 @@
+
+// POCPieceGenerator.cpp
+
+// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 50, 0}
+
+#include "Globals.h"
+#include "POCPieceGenerator.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+/** POC pieces are simple boxes that have connectors in the middle of their walls.
+Each wall has one connector, there are 3 connector types that get assigned semi-randomly.
+The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass
+and each connector is uses a different color wool frame. */
+class cPOCPiece :
+ public cPiece
+{
+public:
+ cPOCPiece(int a_SizeXZ, int a_Height) :
+ m_SizeXZ(a_SizeXZ),
+ m_Height(a_Height)
+ {
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, 0, 0, BLOCK_FACE_ZM));
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, m_SizeXZ - 1, 1, BLOCK_FACE_ZP));
+ m_Connectors.push_back(cConnector(0, a_Height / 2, m_SizeXZ / 2, 2, BLOCK_FACE_XM));
+ m_Connectors.push_back(cConnector(m_SizeXZ - 1, a_Height - 1, m_SizeXZ / 2, m_SizeXZ % 3, BLOCK_FACE_XP));
+ }
+
+
+ /** Imprints the piece in the specified chunk. Assumes they intersect. */
+ void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations)
+ {
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ Vector3i Min = a_Pos;
+ Min.Move(-BlockX, 0, -BlockZ);
+ Vector3i Max = Min;
+ Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ ASSERT(Min.x < cChunkDef::Width);
+ ASSERT(Min.z < cChunkDef::Width);
+ ASSERT(Max.x >= 0);
+ ASSERT(Max.z >= 0);
+ if (Min.x >= 0)
+ {
+ // Draw the XM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Min.z >= 0)
+ {
+ // Draw the ZM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.x < cChunkDef::Width)
+ {
+ // Draw the XP wall:
+ a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.z < cChunkDef::Width)
+ {
+ // Draw the ZP wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+
+ // Draw all the connectors:
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z);
+ Conn.m_Pos.Move(-BlockX, 0, -BlockZ);
+ if (
+ (Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) &&
+ (Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width)
+ )
+ {
+ a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16);
+ }
+
+ /*
+ // TODO: Frame the connectors
+ switch (itr->m_Direction)
+ {
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
+ {
+ // TODO
+ break;
+ }
+
+ case BLOCK_FACE_ZM:
+ case BLOCK_FACE_ZP:
+ {
+ // TODO
+ break;
+ }
+ }
+ */
+ } // for itr - m_Connectors[]
+ }
+
+protected:
+ int m_SizeXZ;
+ int m_Height;
+ cConnectors m_Connectors;
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override
+ {
+ return m_Connectors;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_SizeXZ, m_Height, m_SizeXZ);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumRotations) const override
+ {
+ return true;
+ }
+};
+
+
+
+
+
+/*
+static void DebugPieces(const cPlacedPieces & a_Pieces)
+{
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx)
+ {
+ const cCuboid & HitBox = (*itr)->GetHitBox();
+ printf(" %u: %d rotations, {%d - %d, %d - %d}\n",
+ idx, (*itr)->GetNumCCWRotations(),
+ HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z
+ );
+ } // for itr - a_Pieces[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPOCPieceGenerator:
+
+cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
+ m_Seed(a_Seed)
+{
+ // Prepare a vector of available pieces:
+ m_AvailPieces.push_back(new cPOCPiece(5, 3));
+ m_AvailPieces.push_back(new cPOCPiece(7, 5));
+ m_AvailPieces.push_back(new cPOCPiece(9, 5));
+ m_AvailPieces.push_back(new cPOCPiece(5, 7));
+
+ // Generate the structure:
+ cBFSPieceGenerator Gen(*this, a_Seed);
+ Gen.PlacePieces(0, 50, 0, 6, m_Pieces);
+
+ // DebugPieces(m_Pieces);
+
+ // Get the smallest cuboid encompassing the entire generated structure:
+ cCuboid Bounds(0, 50, 0, 0, 50, 0);
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ Vector3i MinCoords = (*itr)->GetCoords();
+ Bounds.Engulf(MinCoords);
+ Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize());
+ } // for itr - m_Pieces[]
+ m_Bounds = Bounds;
+}
+
+
+
+
+
+cPOCPieceGenerator::~cPOCPieceGenerator()
+{
+ cPieceGenerator::FreePieces(m_Pieces);
+}
+
+
+
+
+
+void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ if (
+ (BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure
+ (BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure
+ )
+ {
+ return;
+ }
+
+ // Imprint each piece in the chunk:
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const Vector3i & Pos = (*itr)->GetCoords();
+ Vector3i Size = (*itr)->GetPiece().GetSize();
+ if (((*itr)->GetNumCCWRotations() % 2) == 1)
+ {
+ std::swap(Size.x, Size.z);
+ }
+ if (
+ (Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) ||
+ (Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ)
+ )
+ {
+ // This piece doesn't intersect the chunk
+ continue;
+ }
+
+ ((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations());
+ } // for itr - m_Pieces[]
+ a_ChunkDesc.UpdateHeightmap();
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType)
+{
+ // Each piece has each connector
+ return m_AvailPieces;
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetStartingPieces(void)
+{
+ // Any piece can be a starting piece
+ return m_AvailPieces;
+}
+
+
+
+
+
+void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cPOCPieceGenerator::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/POCPieceGenerator.h b/src/Generating/POCPieceGenerator.h
new file mode 100644
index 000000000..de3114ce0
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.h
@@ -0,0 +1,54 @@
+
+// POCPieceGenerator.h
+
+// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 100, 0}
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "ComposableGenerator.h"
+
+
+
+
+
+class cPOCPieceGenerator :
+ public cFinishGen,
+ protected cPiecePool
+{
+public:
+ cPOCPieceGenerator(int a_Seed);
+ ~cPOCPieceGenerator();
+
+protected:
+ int m_Seed;
+
+ /** The pieces from which the generated structure is built. */
+ cPieces m_AvailPieces;
+
+ /** The placed pieces of the generated structure. */
+ cPlacedPieces m_Pieces;
+
+ /** Bounds of the complete structure, to save on processing outside chunks. */
+ cCuboid m_Bounds;
+
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
+
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp
new file mode 100644
index 000000000..8999a5ff7
--- /dev/null
+++ b/src/Generating/PieceGenerator.cpp
@@ -0,0 +1,625 @@
+
+// PieceGenerator.cpp
+
+// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+#include "Globals.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Self-test:
+
+static class cPieceGeneratorSelfTest :
+ public cPiecePool
+{
+public:
+ cPieceGeneratorSelfTest(void)
+ {
+ // Prepare the internal state:
+ InitializePieces();
+
+ // Generate:
+ cBFSPieceGenerator Gen(*this, 0);
+ cPlacedPieces OutPieces;
+ Gen.PlacePieces(500, 50, 500, 3, OutPieces);
+
+ // Print out the pieces:
+ printf("OutPieces.size() = " SIZE_T_FMT "\n", OutPieces.size());
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx)
+ {
+ const Vector3i & Coords = (*itr)->GetCoords();
+ cCuboid Hitbox = (*itr)->GetHitBox();
+ Hitbox.Sort();
+ printf(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx,
+ Coords.x, Coords.y, Coords.z,
+ (*itr)->GetNumCCWRotations(),
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ } // itr - OutPieces[]
+ printf("Done.\n");
+
+ // Free the placed pieces properly:
+ Gen.FreePieces(OutPieces);
+ }
+
+ ~cPieceGeneratorSelfTest()
+ {
+ // Dealloc all the pieces:
+ for (cPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_Pieces.clear();
+ }
+
+protected:
+ class cTestPiece :
+ public cPiece
+ {
+ int m_Size;
+ public:
+ cTestPiece(int a_Size) :
+ m_Size(a_Size)
+ {
+ }
+
+ virtual cConnectors GetConnectors(void) const override
+ {
+ // Each piece has 4 connectors, one of each type, plus one extra, at the center of its walls:
+ cConnectors res;
+ res.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM));
+ res.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP));
+ res.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM));
+ res.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP));
+ return res;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_Size, 5, m_Size);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_Size - 1, 4, m_Size - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumCCWRotations) const override
+ {
+ return true;
+ }
+ };
+
+ cPieces m_Pieces;
+
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
+ {
+ // Each piece contains each connector
+ return m_Pieces;
+ }
+
+
+ virtual cPieces GetStartingPieces(void) override
+ {
+ return m_Pieces;
+ }
+
+
+ virtual void PiecePlaced(const cPiece & a_Piece) override
+ {
+ UNUSED(a_Piece);
+ }
+
+
+ virtual void Reset(void) override
+ {
+ }
+
+
+ void InitializePieces(void)
+ {
+ m_Pieces.push_back(new cTestPiece(5));
+ m_Pieces.push_back(new cTestPiece(7));
+ m_Pieces.push_back(new cTestPiece(9));
+ }
+} g_Test;
+
+#endif // SELF_TEST
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece:
+
+
+Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const
+{
+ Vector3i Size = GetSize();
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ return a_Pos;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1);
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1);
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x);
+ }
+ }
+ ASSERT(!"Unhandled rotation");
+ return a_Pos;
+}
+
+
+
+
+
+cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ cPiece::cConnector res(a_Connector);
+
+ // Rotate the res connector:
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ break;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ res.m_Direction = RotateBlockFaceCCW(res.m_Direction);
+ break;
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ res.m_Direction = MirrorBlockFaceY(res.m_Direction);
+ break;
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ res.m_Direction = RotateBlockFaceCW(res.m_Direction);
+ break;
+ }
+ }
+ res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations);
+
+ // Move the res connector:
+ res.m_Pos.x += a_MoveX;
+ res.m_Pos.y += a_MoveY;
+ res.m_Pos.z += a_MoveZ;
+
+ return res;
+}
+
+
+
+
+
+cCuboid cPiece::RotateHitBoxToConnector(
+ const cPiece::cConnector & a_MyConnector,
+ const Vector3i & a_ToConnectorPos,
+ int a_NumCCWRotations
+) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations);
+ ConnPos = a_ToConnectorPos - ConnPos;
+ return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z);
+}
+
+
+
+
+
+cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ cCuboid res = GetHitBox();
+ res.p1 = RotatePos(res.p1, a_NumCCWRotations);
+ res.p2 = RotatePos(res.p2, a_NumCCWRotations);
+ res.p1.Move(a_MoveX, a_MoveY, a_MoveZ);
+ res.p2.Move(a_MoveX, a_MoveY, a_MoveZ);
+ return res;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece::cConnector:
+
+cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_X, a_Y, a_Z),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_Pos),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPlacedPiece:
+
+cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) :
+ m_Parent(a_Parent),
+ m_Piece(&a_Piece),
+ m_Coords(a_Coords),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+ m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
+ m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
+ m_HitBox.Sort();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator:
+
+cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ m_PiecePool(a_PiecePool),
+ m_Noise(a_Seed),
+ m_Seed(a_Seed)
+{
+}
+
+
+
+
+
+void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces)
+{
+ for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - a_PlacedPieces[]
+ a_PlacedPieces.clear();
+}
+
+
+
+
+
+cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors)
+{
+ m_PiecePool.Reset();
+ int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7;
+
+ // Choose a random one of the starting pieces:
+ cPieces StartingPieces = m_PiecePool.GetStartingPieces();
+ cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()];
+ rnd = rnd >> 16;
+
+ // Choose a random supported rotation:
+ int Rotations[4] = {0};
+ int NumRotations = 1;
+ for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
+ {
+ if (StartingPiece->CanRotateCCW(i))
+ {
+ Rotations[NumRotations] = i;
+ NumRotations += 1;
+ }
+ }
+ int Rotation = Rotations[rnd % NumRotations];
+
+ cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
+
+ // Place the piece's connectors into a_OutConnectors:
+ const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
+ {
+ a_OutConnectors.push_back(
+ cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, a_BlockY, a_BlockZ))
+ );
+ }
+
+ return res;
+}
+
+
+
+
+
+bool cPieceGenerator::TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece,
+ const cPiece::cConnector & a_Connector,
+ cPlacedPieces & a_OutPieces,
+ cPieceGenerator::cFreeConnectors & a_OutConnectors
+)
+{
+ // Translation of direction - direction -> number of CCW rotations needed:
+ // You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite)
+ static const int DirectionRotationTable[6][6] =
+ {
+ /* YM, YP, ZM, ZP, XM, XP */
+ /* YM */ { 0, 0, 0, 0, 0, 0},
+ /* YP */ { 0, 0, 0, 0, 0, 0},
+ /* ZM */ { 0, 0, 2, 0, 1, 3},
+ /* ZP */ { 0, 0, 0, 2, 3, 1},
+ /* XM */ { 0, 0, 3, 1, 2, 0},
+ /* XP */ { 0, 0, 1, 3, 0, 2},
+ };
+
+ // Get a list of available connections:
+ const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
+ cConnections Connections;
+ cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type);
+ Connections.reserve(AvailablePieces.size());
+ Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
+ AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
+
+ /*
+ // DEBUG:
+ printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
+ //*/
+
+ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
+ {
+ cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
+ for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
+ {
+ if (itrC->m_Type != a_Connector.m_Type)
+ {
+ continue;
+ }
+ // This is a same-type connector, find out how to rotate to it:
+ int NumCCWRotations = RotTable[itrC->m_Direction];
+ if (!(*itrP)->CanRotateCCW(NumCCWRotations))
+ {
+ // Doesn't support this rotation
+ continue;
+ }
+ if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
+ {
+ // Doesn't fit in this rotation
+ continue;
+ }
+ Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
+ } // for itrC - Connectors[]
+ } // for itrP - AvailablePieces[]
+ if (Connections.empty())
+ {
+ // No available connections, bail out
+ return false;
+ }
+
+ // Choose a random connection from the list:
+ int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
+ cConnection & Conn = Connections[rnd % Connections.size()];
+
+ // Place the piece:
+ /*
+ // DEBUG
+ printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
+ Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
+ BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
+ Conn.m_NumCCWRotations
+ );
+ //*/
+
+ Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
+ ConnPos -= NewPos;
+ cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
+ a_OutPieces.push_back(PlacedPiece);
+
+ // Add the new piece's connectors to the list of free connectors:
+ cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
+
+ /*
+ // DEBUG:
+ printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
+ //*/
+
+ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
+ {
+ // This is the connector through which we have been connected to the parent, don't add
+ continue;
+ }
+ a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
+ }
+
+ return true;
+}
+
+
+
+
+
+bool cPieceGenerator::CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector,
+ const Vector3i & a_ToPos,
+ const cPiece & a_Piece,
+ const cPiece::cConnector & a_NewConnector,
+ int a_NumCCWRotations,
+ const cPlacedPieces & a_OutPieces
+)
+{
+ // For each placed piece, test the hitbox against the new piece:
+ cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
+ RotatedHitBox.Sort();
+ for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
+ {
+ if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+//*
+// DEBUG:
+void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
+{
+ printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
+ size_t idx = 0;
+ for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx)
+ {
+ printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
+ idx,
+ itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
+ itr->m_Connector.m_Type,
+ BlockFaceToString(itr->m_Connector.m_Direction).c_str(),
+ itr->m_Piece->GetDepth()
+ );
+ } // for itr - a_ConnectorPool[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cConnection:
+
+cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
+ m_Piece(&a_Piece),
+ m_Connector(a_Connector),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cFreeConnector:
+
+cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
+ m_Piece(a_Piece),
+ m_Connector(a_Connector)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cBFSPieceGenerator:
+
+cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ super(a_PiecePool, a_Seed)
+{
+}
+
+
+
+
+
+void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
+{
+ a_OutPieces.clear();
+ cFreeConnectors ConnectorPool;
+
+ // Place the starting piece:
+ a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool));
+
+ /*
+ // DEBUG:
+ printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
+ cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, 0);
+ //*/
+
+ // Place pieces at the available connectors:
+ /*
+ Instead of removing them one by one from the pool, we process them sequentially and take note of the last
+ processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
+ of the connectors is removed.
+ */
+ size_t NumProcessed = 0;
+ while (ConnectorPool.size() > NumProcessed)
+ {
+ cFreeConnector & Conn = ConnectorPool[NumProcessed];
+ if (Conn.m_Piece->GetDepth() < a_MaxDepth)
+ {
+ if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
+ {
+ /*
+ // DEBUG:
+ const cPlacedPiece * NewPiece = a_OutPieces.back();
+ const Vector3i & Coords = NewPiece->GetCoords();
+ printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
+ cCuboid Hitbox = NewPiece->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, NumProcessed + 1);
+ //*/
+ }
+ }
+ NumProcessed++;
+ if (NumProcessed > 1000)
+ {
+ ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + NumProcessed);
+ NumProcessed = 0;
+ }
+ }
+}
+
+
+
+
diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h
new file mode 100644
index 000000000..bef9d3463
--- /dev/null
+++ b/src/Generating/PieceGenerator.h
@@ -0,0 +1,247 @@
+
+// PieceGenerator.h
+
+// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+/*
+Each uses a slightly different approach to generating:
+ - DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore),
+ then starts looking at adjacent connectors (like depth-first search).
+ - BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
+ thus possibly extending the pool of open connectors (like breadth-first search).
+*/
+
+
+
+
+
+#pragma once
+
+#include "../Defines.h"
+#include "../Cuboid.h"
+#include "../Noise.h"
+
+
+
+
+
+/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */
+class cPiece
+{
+public:
+ // Force a virtual destructor in all descendants
+ virtual ~cPiece() {}
+
+ struct cConnector
+ {
+ /** Position relative to the piece */
+ Vector3i m_Pos;
+
+ /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */
+ int m_Type;
+
+ /** Direction in which the connector is facing.
+ Will be matched by the opposite direction for the connecting connector. */
+ eBlockFace m_Direction;
+
+ cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction);
+ cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction);
+ };
+
+ typedef std::vector<cConnector> cConnectors;
+
+ /** Returns all of the available connectors that the piece has.
+ Each connector has a (relative) position in the piece, and a type associated with it. */
+ virtual cConnectors GetConnectors(void) const = 0;
+
+ /** Returns the dimensions of this piece.
+ The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */
+ virtual Vector3i GetSize(void) const = 0;
+
+ /** Returns the "hitbox" of this piece.
+ A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */
+ virtual cCuboid GetHitBox(void) const = 0;
+
+ /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */
+ virtual bool CanRotateCCW(int a_NumRotations) const = 0;
+
+ /** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */
+ Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const;
+
+ /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */
+ cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+
+ /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */
+ cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const;
+
+ /** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */
+ cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+};
+
+typedef std::vector<cPiece *> cPieces;
+
+
+
+
+
+/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
+placed and adjust the returned piece vectors. */
+class cPiecePool
+{
+public:
+ // Force a virtual destructor in all descendants:
+ virtual ~cPiecePool() {}
+
+ /** Returns a list of pieces that contain the specified connector type.
+ The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
+
+ /** Returns the pieces that should be used as the starting point.
+ Multiple starting points are supported, one of the returned piece will be chosen. */
+ virtual cPieces GetStartingPieces(void) = 0;
+
+ /** Called after a piece is placed, to notify the pool that it has been used.
+ The pool may adjust the pieces it will return the next time. */
+ virtual void PiecePlaced(const cPiece & a_Piece) = 0;
+
+ /** Called when the pool has finished the current structure and should reset any piece-counters it has
+ for a new structure. */
+ virtual void Reset(void) = 0;
+};
+
+
+
+
+
+/** Represents a single piece that has been placed to specific coords in the world. */
+class cPlacedPiece
+{
+public:
+ cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
+
+ const cPiece & GetPiece (void) const { return *m_Piece; }
+ const Vector3i & GetCoords (void) const { return m_Coords; }
+ int GetNumCCWRotations(void) const { return m_NumCCWRotations; }
+ const cCuboid & GetHitBox (void) const { return m_HitBox; }
+ int GetDepth (void) const { return m_Depth; }
+
+protected:
+ const cPlacedPiece * m_Parent;
+ const cPiece * m_Piece;
+ Vector3i m_Coords;
+ int m_NumCCWRotations;
+ cCuboid m_HitBox;
+ int m_Depth;
+};
+
+typedef std::vector<cPlacedPiece *> cPlacedPieces;
+
+
+
+
+
+class cPieceGenerator
+{
+public:
+ cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Cleans up all the memory used by the placed pieces.
+ Call this utility function instead of freeing the items on your own. */
+ static void FreePieces(cPlacedPieces & a_PlacedPieces);
+
+protected:
+ /** The type used for storing a connection from one piece to another, while building the piece tree. */
+ struct cConnection
+ {
+ cPiece * m_Piece; // The piece being connected
+ cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
+ int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
+ };
+ typedef std::vector<cConnection> cConnections;
+
+ /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
+ struct cFreeConnector
+ {
+ cPlacedPiece * m_Piece;
+ cPiece::cConnector m_Connector;
+
+ cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
+ };
+ typedef std::vector<cFreeConnector> cFreeConnectors;
+
+
+ cPiecePool & m_PiecePool;
+ cNoise m_Noise;
+ int m_Seed;
+
+
+ /** Selects a starting piece and places it, including the rotations.
+ Also puts the piece's connectors in a_OutConnectors. */
+ cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors);
+
+ /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
+ bool TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
+ const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
+ cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
+ cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
+ );
+
+ /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
+ and number of CCW rotations.
+ a_ExistingConnector is in world-coords and is already rotated properly
+ a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
+ a_NewConnector is in the original (non-rotated) coords.
+ Returns true if the piece fits, false if not. */
+ bool CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector, // The existing connector
+ const Vector3i & a_ToPos, // The position on which the new connector should be placed
+ const cPiece & a_Piece, // The new piece
+ const cPiece::cConnector & a_NewConnector, // The connector of the new piece
+ int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
+ const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
+ );
+
+ /** DEBUG: Outputs all the connectors in the pool into stdout.
+ a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
+ void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
+} ;
+
+
+
+
+
+class cBFSPieceGenerator :
+ public cPieceGenerator
+{
+ typedef cPieceGenerator super;
+
+public:
+ cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
+
+class cDFSPieceGenerator :
+ public cPieceGenerator
+{
+public:
+ cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
new file mode 100644
index 000000000..131b6acb2
--- /dev/null
+++ b/src/Generating/Prefab.cpp
@@ -0,0 +1,316 @@
+
+// Prefab.cpp
+
+/*
+Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+*/
+
+#include "Globals.h"
+#include "Prefab.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+// Create one static prefab to test the parser:
+static const cPrefab::sDef g_TestPrefabDef =
+{
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* 0 */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 3, 2: 4\n"
+ "0: 2, 3, 0: 2\n",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msImprint
+};
+
+static cPrefab g_TestPrefab(g_TestPrefabDef);
+#endif
+
+
+
+
+
+cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
+ m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
+ m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
+ m_AllowedRotations(a_Def.m_AllowedRotations),
+ m_MergeStrategy(a_Def.m_MergeStrategy)
+{
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_Def.m_CharMap);
+ ParseBlockImage(cm, a_Def.m_Image);
+ ParseConnectors(a_Def.m_Connectors);
+
+ // 1 CCW rotation:
+ if ((m_AllowedRotations & 0x01) != 0)
+ {
+ m_BlockArea[1].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[1].RotateCCW();
+ }
+
+ // 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
+ if ((m_AllowedRotations & 0x02) != 0)
+ {
+ m_BlockArea[2].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[2].MirrorXY();
+ m_BlockArea[2].MirrorYZ();
+ }
+
+ // 3 CCW rotations = 1 CW rotation:
+ if ((m_AllowedRotations & 0x04) != 0)
+ {
+ m_BlockArea[3].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[3].RotateCW();
+ }
+}
+
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
+{
+ Vector3i Placement = a_Placement->GetCoords();
+ int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
+ int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
+ Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
+ a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+
+}
+
+
+
+
+
+bool cPrefab::HasConnectorType(int a_ConnectorType) const
+{
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Type == a_ConnectorType)
+ {
+ return true;
+ }
+ } // for itr - m_Connectors[]
+ return false;
+}
+
+
+
+
+
+void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
+{
+ ASSERT(a_CharMapDef != NULL);
+
+ // Initialize the charmap to all-invalid values:
+ for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
+ {
+ a_CharMapOut[i].m_BlockType = 0;
+ a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise
+ }
+
+ // Process the lines in the definition:
+ AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ AStringVector CharDef = StringSplitAndTrim(*itr, ":");
+ size_t NumElements = CharDef.size();
+ if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
+ {
+ LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ unsigned char Src = (unsigned char)CharDef[0][0];
+ ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet?
+ a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ NIBBLETYPE BlockMeta = 0;
+ if ((NumElements >= 3) && !CharDef[2].empty())
+ {
+ BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
+ ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
+ }
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
+ } // for itr - Lines[]
+}
+
+
+
+
+
+void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
+{
+ // Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
+ for (int y = 0; y < m_Size.y; y++)
+ {
+ for (int z = 0; z < m_Size.z; z++)
+ {
+ const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
+ for (int x = 0; x < m_Size.x; x++)
+ {
+ const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
+ ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
+ m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+{
+ ASSERT(a_ConnectorsDef != NULL);
+
+ AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ continue;
+ }
+ // Split into components: "Type: X, Y, Z: Face":
+ AStringVector Defs = StringSplitAndTrim(*itr, ":");
+ if (Defs.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
+ if (Coords.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
+ continue;
+ }
+
+ // Check that the BlockFace is within range:
+ int BlockFace = atoi(Defs[2].c_str());
+ if ((BlockFace < 0) || (BlockFace >= 6))
+ {
+ LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
+ continue;
+ }
+
+ // Add the connector:
+ m_Connectors.push_back(cPiece::cConnector(
+ atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()), // Connector pos
+ atoi(Defs[0].c_str()), // Connector type
+ (eBlockFace)BlockFace
+ ));
+ } // for itr - Lines[]
+}
+
+
+
+
+
+cPiece::cConnectors cPrefab::GetConnectors(void) const
+{
+ return m_Connectors;
+}
+
+
+
+
+
+Vector3i cPrefab::GetSize(void) const
+{
+ return m_Size;
+}
+
+
+
+
+
+cCuboid cPrefab::GetHitBox(void) const
+{
+ return m_HitBox;
+}
+
+
+
+
+
+bool cPrefab::CanRotateCCW(int a_NumRotations) const
+{
+ // Either zero rotations
+ // Or the proper bit in m_AllowedRotations is set
+ return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
+}
+
+
+
+
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
new file mode 100644
index 000000000..04c4f09da
--- /dev/null
+++ b/src/Generating/Prefab.h
@@ -0,0 +1,105 @@
+
+// Prefab.h
+
+/*
+Declares the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+The class can be constructed from data that is stored directly in the executable, in a sPrefabDef structure
+declared in this file as well; the Gallery server exports areas in this format.
+*/
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "../BlockArea.h"
+
+
+
+
+
+// fwd:
+class cChunkDesc;
+
+
+
+
+
+class cPrefab :
+ public cPiece
+{
+public:
+ struct sDef
+ {
+ int m_SizeX;
+ int m_SizeY;
+ int m_SizeZ;
+ const char * m_CharMap;
+ const char * m_Image;
+ const char * m_Connectors;
+ int m_AllowedRotations;
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+ };
+
+ cPrefab(const sDef & a_Def);
+
+ /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
+ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
+
+ /** Returns true if the prefab has any connector of the specified type. */
+ bool HasConnectorType(int a_ConnectorType) const;
+
+protected:
+ /** Packs complete definition of a single block, for per-letter assignment. */
+ struct sBlockTypeDef
+ {
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ };
+
+ /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
+ typedef sBlockTypeDef CharMap[256];
+
+
+ /** The cBlockArea that contains the block definitions for the prefab.
+ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
+ cBlockArea m_BlockArea[4];
+
+ /** The size of the prefab */
+ Vector3i m_Size;
+
+ /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ cCuboid m_HitBox;
+
+ /** The connectors through which the piece connects to other pieces */
+ cConnectors m_Connectors;
+
+ /** Bitmask, bit N set -> N rotations CCW supported */
+ int m_AllowedRotations;
+
+ /** The merge strategy to use when drawing the prefab into a block area */
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override;
+ virtual Vector3i GetSize(void) const override;
+ virtual cCuboid GetHitBox(void) const override;
+ virtual bool CanRotateCCW(int a_NumRotations) const override;
+
+ /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */
+ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef);
+
+ /** Parses the Image in the definition into m_BlockArea[0]'s block types and metas, using the specified CharMap. */
+ void ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage);
+
+ /** Parses the connectors definition text into m_Connectors member. */
+ void ParseConnectors(const char * a_ConnectorsDef);
+};
+
+
+
+
diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt
new file mode 100644
index 000000000..1e60447e7
--- /dev/null
+++ b/src/Generating/Prefabs/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../../")
+
+file(GLOB SOURCE
+ "*.cpp"
+)
+
+add_library(Generating_Prefabs ${SOURCE})
+
+target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks)
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp
new file mode 100644
index 000000000..5e8685e32
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp
@@ -0,0 +1,2758 @@
+
+// NetherFortPrefabs.cpp
+
+// Defines all the prefabs for nether forts
+
+#include "Globals.h"
+#include "NetherFortPrefabs.h"
+
+
+
+
+
+/*
+The nether fortress has two types of connectors, Outer and Inner. Outer is Type 0, Inner is Type 1.
+*/
+
+
+
+
+
+const cPrefab::sDef g_NetherFortPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyCorridor:
+ // The data has been exported from gallery Nether, area index 37, ID 288
+ {
+ // Size:
+ 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 19: 0\n" /* sponge */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 2\n" /* netherbrickstairs */
+ "i:114: 3\n" /* netherbrickstairs */
+ "j:114: 0\n" /* netherbrickstairs */
+ "k:114: 1\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "bbbbaaaaabbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa.aaa.aaaa"
+ "bbcdaaaaadebb"
+ "bbbcdddddebbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaa.fff.aaaa"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+
+ // Level 4
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bbg.......gbb"
+ "bbg.......gbb"
+ "bbgggggggggbb"
+
+ // Level 5
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 6
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 7
+ "hhhhhhhhhhhhh"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "iijaaaaaaaiii"
+ "bbjiiiiiiikbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb",
+
+ // Connections:
+ "1: 0, 2, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyCorridor
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyTee2:
+ // The data has been exported from gallery Nether, area index 38, ID 289
+ {
+ // Size:
+ 13, 7, 11, // SizeX = 13, SizeY = 7, SizeZ = 11
+
+ // Block definitions:
+ "a: 19: 0\n" /* sponge */
+ "b:112: 0\n" /* netherbrick */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 0\n" /* netherbrickstairs */
+ "i:114: 1\n" /* netherbrickstairs */
+ "j:114: 2\n" /* netherbrickstairs */
+ "k:114: 3\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbb.bbb.bbbb"
+ "aacdbbbbbdeaa"
+ "aaacdddddeaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaab...baaaa"
+ "aaaab...baaaa"
+ "bbbbb...bbbbb"
+ "............."
+ "............."
+ "............."
+ "bbbb.fff.bbbb"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+
+ // Level 4
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aag.......gaa"
+ "aag.......gaa"
+ "aagggggggggaa"
+
+ // Level 5
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 6
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 7
+ "aaaahbbbiaaaa"
+ "aaaahbbbiaaaa"
+ "jjjjjbbbjjjjj"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "kkhbbbbbbbkkk"
+ "aahkkkkkkkiaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 2, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 4: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 2, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyTee2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatform
+ // The data has been exported from gallery Nether, area index 26, ID 276
+ {
+ // Size:
+ 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 52: 0\n" /* mobspawner */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ ".........."
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 2
+ ".........."
+ "aaaaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 3
+ "....aaaaaa"
+ "aaaaaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "aaaaaaaaaa"
+ "....aaaaaa"
+
+ // Level 4
+ "....aaaaaa"
+ "..aaa....a"
+ ".........a"
+ "......b..a"
+ ".........a"
+ "..aaa....a"
+ "....aaaaaa"
+
+ // Level 5
+ "....cccccc"
+ "...cc....c"
+ ".........c"
+ ".........c"
+ ".........c"
+ "...cc....c"
+ "....cccccc"
+
+ // Level 6
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+
+ // Level 7
+ ".........."
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+ "..........",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatform
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatformOverhang:
+ // The data has been exported from gallery Nether, area index 20, ID 162
+ {
+ // Size:
+ 14, 9, 7, // SizeX = 14, SizeY = 9, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */
+ "f:114: 0\n" /* netherbrickstairs */
+ "g:114: 4\n" /* netherbrickstairs */
+ "h:113: 0\n" /* netherbrickfence */
+ "i: 52: 0\n" /* mobspawner */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 4
+ "mmmmmmmmmmmmmm"
+ "dddddddmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "eeeeeeemmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 5
+ "mmmmmmmmmmmmmm"
+ "aaaaaaadmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaaemmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 6
+ "mmmmmmmmmmmmmm"
+ "aaaaaaaabddddm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "aaaaaaaaabeebm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 7
+ "mmmmmmmmgdddbm"
+ "......aaaaaaad"
+ ".......faaaaab"
+ ".......faaaaab"
+ ".......faaaaab"
+ "......aaaaaaae"
+ "mmmmmmmmgeeebm"
+
+ // Level 8
+ "mmmmmmmmaaaaam"
+ "......haa...aa"
+ ".............a"
+ "..........i..a"
+ ".............a"
+ "......haa...aa"
+ "mmmmmmmmaaaaam"
+
+ // Level 9
+ "mmmmmmmmhhhhhm"
+ "......hhh...hh"
+ ".............h"
+ ".............h"
+ ".............h"
+ "......hhh...hh"
+ "mmmmmmmmhhhhhm",
+
+ // Connections:
+ "0: 0, 5, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatformOverhang
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrossing:
+ // The data has been exported from gallery Nether, area index 17, ID 159
+ {
+ // Size:
+ 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 7\n" /* netherbrickstairs */
+ "c:114: 5\n" /* netherbrickstairs */
+ "d:114: 4\n" /* netherbrickstairs */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f: 44:14\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "eeeeeeaaaeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "bbbbbdaaacbbbbb"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+
+ // Level 5
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "aaaaaa...aaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 7: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 7, 5, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 14, 5, 7: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrossing
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble1:
+ // The data has been exported from gallery Nether, area index 19, ID 161
+ {
+ // Size:
+ 9, 6, 5, // SizeX = 9, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "........."
+ "aa......."
+ "aa......."
+ "aa......."
+ "........."
+
+ // Level 2
+ "........."
+ "aab......"
+ "aab......"
+ "aab......"
+ "........."
+
+ // Level 3
+ "........."
+ "aaabc...."
+ "aaabc...."
+ "aaabc...."
+ "........."
+
+ // Level 4
+ "ddddddd.."
+ "aaaaaaaa."
+ "aaaaaaaaa"
+ "aaaaaaa.."
+ "eeeee...."
+
+ // Level 5
+ "aaaaaaaaa"
+ "aaaaa...."
+ "aaaaaa..."
+ "aaaaaa..."
+ "aaaaaaaa."
+
+ // Level 6
+ "aaaaaa..."
+ "........."
+ "........."
+ "........."
+ "aaaaaaa..",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble1
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble2
+ // The data has been exported from gallery Nether, area index 18, ID 160
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "............."
+ "aa..........."
+ "aa..........."
+ "aa..........."
+ "............."
+
+ // Level 2
+ "............."
+ "aab.........."
+ "aab.........."
+ "aab.........."
+ "............."
+
+ // Level 3
+ "............."
+ "aaabc........"
+ "aaabc........"
+ "aaabc........"
+ "............."
+
+ // Level 4
+ "ddddddddd...."
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaa."
+ "eeeeeeeee...."
+
+ // Level 5
+ "aaaaaaaaaaaa."
+ "aaaaaaaaaa..."
+ "aaaaaaaaaaa.."
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaa...."
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaa...",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeSegment:
+ // The data has been exported from gallery Nether, area index 16, ID 158
+ {
+ // Size:
+ 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d: 44:14\n" /* step */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 4
+ "eeeeeeeeeeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffffffffffff"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeSegment
+
+
+ // BridgeTee:
+ // The data has been exported from gallery Nether, area index 39, ID 290
+ {
+ // Size:
+ 15, 8, 10, // SizeX = 15, SizeY = 8, SizeZ = 10
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e: 44:14\n" /* step */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "ddddddddddddddd"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffcaaabfffff"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 9: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeTee
+
+
+ // Corridor11:
+ // The data has been exported from gallery Nether, area index 36, ID 287
+ {
+ // Size:
+ 11, 6, 5, // SizeX = 11, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "..........."
+ "..........."
+ "..........."
+ "aaaaaaaaaaa"
+
+ // Level 3
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 4
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 5
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 6
+ "ccccccccccc"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "ddddddddddd",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor11
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor13:
+ // The data has been exported from gallery Nether, area index 35, ID 286
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ ".: 0: 0\n" /* air */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 4
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 5
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 6
+ "ddddddddddddd"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "eeeeeeeeeeeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor13
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "a.........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g: 54: 5\n" /* chest */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "ag........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5Chest
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorStairs:
+ // The data has been exported from gallery Nether, area index 12, ID 42
+ {
+ // Size:
+ 9, 13, 5, // SizeX = 9, SizeY = 13, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 0\n" /* netherbrickstairs */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 3
+ "acaaaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "acaaaaaaa"
+
+ // Level 4
+ "acaaaaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "acaaaaaaa"
+
+ // Level 5
+ "acacaaaaa"
+ "....baaaa"
+ "....baaaa"
+ "....baaaa"
+ "acacaaaaa"
+
+ // Level 6
+ "aaacaaaaa"
+ ".....baaa"
+ ".....baaa"
+ ".....baaa"
+ "aaacaaaaa"
+
+ // Level 7
+ "daacacaaa"
+ "a.....baa"
+ "a.....baa"
+ "a.....baa"
+ "eaacacaaa"
+
+ // Level 8
+ "fdaaacaaa"
+ "fa.....ba"
+ "fa.....ba"
+ "fa.....ba"
+ "feaaacaaa"
+
+ // Level 9
+ "ffdaacaca"
+ "ffa......"
+ "ffa......"
+ "ffa......"
+ "ffeaacaca"
+
+ // Level 10
+ "fffdaaaca"
+ "fffa....."
+ "fffa....."
+ "fffa....."
+ "fffeaaaca"
+
+ // Level 11
+ "ffffdaaca"
+ "ffffa...."
+ "ffffa...."
+ "ffffa...."
+ "ffffeaaca"
+
+ // Level 12
+ "fffffdaaa"
+ "fffffa..."
+ "fffffa..."
+ "fffffa..."
+ "fffffeaaa"
+
+ // Level 13
+ "ffffffddd"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 8, 8, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorStairs
+
+
+ // LavaStaircase:
+ // The data has been exported from gallery Nether, area index 28, ID 278
+ {
+ // Size:
+ 15, 11, 15, // SizeX = 15, SizeY = 11, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c: 11: 0\n" /* lava */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaa...aaaa"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaab........a"
+ "accca...aaaa..a"
+ "accca...acca..a"
+ "acccaaaaacca..a"
+ "acccccccccca..a"
+ "acccaaaaacca..a"
+ "accca...acca..a"
+ "accca...aaaa..a"
+ "aaaaab........a"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 3
+ "aaaaaaaa...aaaa"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 4
+ "aaaaaaaa...aaaa"
+ "a.............a"
+ "a.............a"
+ "a..bb.........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..bb.........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaa...aaaa"
+
+ // Level 5
+ "aaaaaaaabbbaaaa"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaabbbaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "...b..........a"
+ "...b..........a"
+ "...b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 8
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 9
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 10
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 11
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 6, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "0: 9, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 9, 1, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircase
+
+
+ // LavaStaircaseBig:
+ // The data has been exported from gallery Nether, area index 31, ID 282
+ {
+ // Size:
+ 12, 15, 15, // SizeX = 12, SizeY = 15, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 10: 0\n" /* lava */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbbaaaaa"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbbaaaaa"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 4
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaa...a"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbbaa...a"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 5
+ "aaaaaaaaaaaa"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaacc....a"
+ "a.....cc...a"
+ "a......c...a"
+ "a......c...."
+ "a......c...."
+ "a......c...."
+ "a......c...a"
+ "a.....cc...a"
+ "aaaaacc....a"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaa"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..cc......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..cc......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 9
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 10
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "...c.......a"
+ "...c.......a"
+ "...c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 11
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 12
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 13
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 14
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 15
+ "aaaaaaaaaaaa"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "aaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 9, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 11, 1, 7: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircaseBig
+
+
+ // MidStaircase:
+ // The data has been exported from gallery Nether, area index 23, ID 165
+ {
+ // Size:
+ 13, 8, 13, // SizeX = 13, SizeY = 8, SizeZ = 13
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 88: 0\n" /* soulsand */
+ "c:115: 7\n" /* netherwartblock */
+ "d:114: 3\n" /* netherbrickstairs */
+ "e:114: 0\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g:114: 2\n" /* netherbrickstairs */
+ "h: 10: 0\n" /* lava */
+ "i:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaacccccaaaa"
+ "addecccccfdda"
+ "...eaaaaad..."
+ "...eaaaaa...."
+ "...eaaaaag..."
+ "agggcccccfgga"
+ "aaaacccccaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "aha.......aha"
+ "aaa.......aaa"
+ "a...........a"
+ "a...........a"
+ "....eaaaa...."
+ "....eaaaa...."
+ "....eaaaa...."
+ "a...........a"
+ "a...........a"
+ "aaa.......aaa"
+ "aha.......aha"
+ "aaaaaaaaaaaaa"
+
+ // Level 4
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ ".....eaaa...."
+ ".....eaaa...."
+ ".....eaaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 5
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "......eaa...."
+ "......eaa...."
+ "......eaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a......ea...a"
+ "a......ea...a"
+ "a......ea...a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "iaiaiaiaiaiai"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a............"
+ "i............"
+ "a............"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "iaiaiaiaiaiai",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 12, 7, 6: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // MidStaircase
+
+
+ // StairsToOpen1:
+ // The data has been exported from gallery Nether, area index 27, ID 277
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "a......"
+ "a......"
+ "a......"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 7, 3: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen1
+
+
+ // StairsToOpen2:
+ // The data has been exported from gallery Nether, area index 8, ID 35
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "......a"
+ "......a"
+ "......a"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 0, 7, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen2
+
+
+ // Tee2x4:
+ // The data has been exported from gallery Nether, area index 40, ID 291
+ {
+ // Size:
+ 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */
+ "1: 12, 1, 4: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee2x4
+
+
+ // Tee4x4:
+ // The data has been exported from gallery Nether, area index 41, ID 292
+ {
+ // Size:
+ 13, 6, 9, // SizeX = 13, SizeY = 6, SizeZ = 9
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee4x4
+
+ // Turret:
+ // The data has been exported from gallery Nether, area index 7, ID 34
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 1, 3: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 3, 1, 6: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Turret
+
+} ; // g_NetherFortPrefabs1
+
+
+
+
+
+const cPrefab::sDef g_NetherFortStartingPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CentralRoom:
+ // The data has been exported from gallery Nether, area index 22, ID 164
+ {
+ // Size:
+ 13, 9, 13, // SizeX = 13, SizeY = 9, SizeZ = 13
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 0: 0\n" /* air */
+ "c: 10: 0\n" /* lava */
+ "d:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbaaabbbaa"
+ "aabbbacabbbaa"
+ "aabbbaaabbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 3
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 4
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 5
+ "adadadddadada"
+ "daaaabbbaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaabbbaaaad"
+ "adadabbbadada"
+
+ // Level 6
+ "adadaaaaadada"
+ "daaaaaaaaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaaaaaaaaad"
+ "adadaaaaadada"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 9
+ "dadadadadadad"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dadadadadadad",
+
+ // Connections:
+ "0: 6, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "1: 6, 1, 12: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ },
+} ; // g_NetherFortStartingPrefabs1
+
+const size_t g_NetherFortPrefabs1Count = ARRAYCOUNT(g_NetherFortPrefabs1);
+const size_t g_NetherFortStartingPrefabs1Count = ARRAYCOUNT(g_NetherFortStartingPrefabs1);
+
+
+
+
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.h b/src/Generating/Prefabs/NetherFortPrefabs.h
new file mode 100644
index 000000000..37a91689d
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.h
@@ -0,0 +1,15 @@
+
+// NetherFortPrefabs.h
+
+// Declares the data used for nether fortress prefabs
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_NetherFortPrefabs1[];
+extern const cPrefab::sDef g_NetherFortStartingPrefabs1[];
+extern const size_t g_NetherFortPrefabs1Count;
+extern const size_t g_NetherFortStartingPrefabs1Count;
diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp
index cfda47e32..e64f55214 100644
--- a/src/Generating/Ravines.cpp
+++ b/src/Generating/Ravines.cpp
@@ -117,7 +117,7 @@ void cStructGenRavines::ClearCache(void)
-void cStructGenRavines::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
diff --git a/src/Generating/Ravines.h b/src/Generating/Ravines.h
index 05164a5b2..c76b9f19f 100644
--- a/src/Generating/Ravines.h
+++ b/src/Generating/Ravines.h
@@ -17,7 +17,7 @@
class cStructGenRavines :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenRavines(int a_Seed, int a_Size);
@@ -37,8 +37,8 @@ protected:
/// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function.
void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines);
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index 47945cc2b..db9d5578c 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -54,7 +54,7 @@ const int NEST_SIZE_GRAVEL = 32;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees:
-void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -306,7 +306,7 @@ int cStructGenTrees::GetNumTrees(
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenOreNests:
-void cStructGenOreNests::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -413,7 +413,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenLakes:
-void cStructGenLakes::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -545,7 +545,7 @@ cStructGenDirectOverhangs::cStructGenDirectOverhangs(int a_Seed) :
-void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{
// If there is no column of the wanted biome, bail out:
if (!HasWantedBiome(a_ChunkDesc))
@@ -578,7 +578,7 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, BaseY, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments:
for (int Segment = BaseY; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@@ -591,7 +591,7 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
@@ -665,7 +665,7 @@ cStructGenDistortedMembraneOverhangs::cStructGenDistortedMembraneOverhangs(int a
-void cStructGenDistortedMembraneOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDistortedMembraneOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{
const NOISE_DATATYPE Frequency = (NOISE_DATATYPE)16;
const NOISE_DATATYPE Amount = (NOISE_DATATYPE)1;
diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h
index 853748bb8..9176bc192 100644
--- a/src/Generating/StructGen.h
+++ b/src/Generating/StructGen.h
@@ -21,7 +21,7 @@
class cStructGenTrees :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) :
@@ -64,8 +64,8 @@ protected:
const cChunkDef::BiomeMap & a_Biomes
);
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -73,7 +73,7 @@ protected:
class cStructGenOreNests :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
@@ -82,8 +82,8 @@ protected:
cNoise m_Noise;
int m_Seed;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq);
} ;
@@ -93,7 +93,7 @@ protected:
class cStructGenLakes :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) :
@@ -112,8 +112,8 @@ protected:
cTerrainHeightGen & m_HeiGen;
int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
/// Creates a lake image for the specified chunk into a_Lake
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake);
@@ -125,7 +125,7 @@ protected:
class cStructGenDirectOverhangs :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDirectOverhangs(int a_Seed);
@@ -134,8 +134,8 @@ protected:
cNoise m_Noise1;
cNoise m_Noise2;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
bool HasWantedBiome(cChunkDesc & a_ChunkDesc) const;
} ;
@@ -145,7 +145,7 @@ protected:
class cStructGenDistortedMembraneOverhangs :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDistortedMembraneOverhangs(int a_Seed);
@@ -156,8 +156,8 @@ protected:
cNoise m_NoiseZ;
cNoise m_NoiseH;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index a660285d1..4909587b1 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -595,7 +595,7 @@ void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise
{
break;
}
- ASSERT(LayerSize < ARRAYCOUNT(BigOs));
+ ASSERT((size_t)LayerSize < ARRAYCOUNT(BigOs));
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
h--;
}
diff --git a/src/Globals.h b/src/Globals.h
index e4737a98a..26a0d87a9 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -29,6 +29,9 @@
// Disabling this warning, because we know what we're doing when we're doing this:
#pragma warning(disable: 4355) // 'this' used in initializer list
+
+ // Disabled because it's useless:
+ #pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member
// 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places
// #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data
@@ -38,6 +41,15 @@
// No alignment needed in MSVC
#define ALIGN_8
#define ALIGN_16
+
+ #define FORMATSTRING(formatIndex, va_argsIndex)
+
+ // MSVC has its own custom version of zu format
+ #define SIZE_T_FMT "%Iu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
+ #define SIZE_T_FMT_HEX "%Ix"
+
+ #define NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
@@ -56,6 +68,14 @@
// Some portability macros :)
#define stricmp strcasecmp
+
+ #define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
+
+ #define SIZE_T_FMT "%zu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
+ #define SIZE_T_FMT_HEX "%zx"
+
+ #define NORETURN __attribute((__noreturn__))
#else
@@ -81,8 +101,15 @@
#endif
+#ifdef _DEBUG
+ #define NORETURNDEBUG NORETURN
+#else
+ #define NORETURNDEBUG
+#endif
+#include <stddef.h>
+
// Integral types with predefined sizes:
typedef long long Int64;
@@ -96,8 +123,23 @@ typedef unsigned short UInt16;
typedef unsigned char Byte;
+// If you get an error about specialization check the size of integral types
+template <typename T, size_t Size, bool x = sizeof(T) == Size>
+class SizeChecker;
+
+template <typename T, size_t Size>
+class SizeChecker<T, Size, true>
+{
+ T v;
+};
+template class SizeChecker<Int64, 8>;
+template class SizeChecker<Int32, 4>;
+template class SizeChecker<Int16, 2>;
+template class SizeChecker<UInt64, 8>;
+template class SizeChecker<UInt32, 4>;
+template class SizeChecker<UInt16, 2>;
// 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
@@ -179,7 +221,7 @@ typedef unsigned char Byte;
#include <memory>
#include <set>
#include <queue>
-
+#include <limits>
@@ -220,15 +262,22 @@ typedef unsigned char Byte;
// Pretty much the same as ASSERT() but stays in Release builds
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
+// Same as assert but in all Self test builds
+#ifdef SELF_TEST
+#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
+#endif
+
-/// A generic interface used mainly in ForEach() functions
+/** A generic interface used mainly in ForEach() functions */
template <typename Type> class cItemCallback
{
public:
- /// Called for each item in the internal list; return true to stop the loop, or false to continue enumerating
+ virtual ~cItemCallback() {}
+
+ /** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
virtual bool Item(Type * a_Type) = 0;
} ;
@@ -246,12 +295,19 @@ T Clamp(T a_Value, T a_Min, T a_Max)
+#ifndef TOLUA_TEMPLATE_BIND
+#define TOLUA_TEMPLATE_BIND(x)
+#endif
+
+
+
+
+
// Common headers (part 2, with macros):
#include "ChunkDef.h"
#include "BiomeDef.h"
#include "BlockID.h"
+#include "BlockInfo.h"
#include "Entities/Effects.h"
-
-
diff --git a/src/Group.cpp b/src/Group.cpp
index 5f1f25782..9c2467144 100644
--- a/src/Group.cpp
+++ b/src/Group.cpp
@@ -38,4 +38,4 @@ void cGroup::InheritFrom( cGroup* a_Group )
void cGroup::ClearPermission()
{
m_Permissions.clear();
-} \ No newline at end of file
+}
diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp
index 5125e7586..33b601e82 100644
--- a/src/GroupManager.cpp
+++ b/src/GroupManager.cpp
@@ -55,16 +55,27 @@ cGroupManager::cGroupManager()
+void cGroupManager::GenerateDefaultUsersIni(cIniFile & a_IniFile)
+{
+ LOGWARN("Regenerating users.ini, all users will be reset");
+ a_IniFile.AddHeaderComment(" This file stores the players' groups.");
+ a_IniFile.AddHeaderComment(" The format is:");
+ a_IniFile.AddHeaderComment(" [PlayerName]");
+ a_IniFile.AddHeaderComment(" Groups = GroupName1, GroupName2, ...");
+
+ a_IniFile.WriteFile("users.ini");
+}
+
+
+
+
+
void cGroupManager::CheckUsers(void)
{
cIniFile IniFile;
if (!IniFile.ReadFile("users.ini"))
{
- LOGWARN("Regenerating users.ini, all users will be reset");
- IniFile.AddHeaderComment(" This is the file in which the group the player belongs to is stored");
- IniFile.AddHeaderComment(" The format is: [PlayerName] | Groups=GroupName");
-
- IniFile.WriteFile("users.ini");
+ GenerateDefaultUsersIni(IniFile);
return;
}
diff --git a/src/GroupManager.h b/src/GroupManager.h
index 377a54c98..9e1689a76 100644
--- a/src/GroupManager.h
+++ b/src/GroupManager.h
@@ -19,6 +19,9 @@ public:
void LoadGroups(void);
void CheckUsers(void);
+ /** Writes the default header to the specified ini file, and saves it as "users.ini". */
+ static void GenerateDefaultUsersIni(cIniFile & a_IniFile);
+
private:
friend class cRoot;
cGroupManager();
diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h
index 6430fbebf..866bed11d 100644
--- a/src/HTTPServer/EnvelopeParser.h
+++ b/src/HTTPServer/EnvelopeParser.h
@@ -19,6 +19,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a full header line is parsed
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0;
} ;
diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h
index a554ca5a4..f2a509cb8 100644
--- a/src/HTTPServer/HTTPFormParser.h
+++ b/src/HTTPServer/HTTPFormParser.h
@@ -36,6 +36,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a new file part is encountered in the form data
virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0;
diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp
index f6f5b0f8b..4e9195a00 100644
--- a/src/HTTPServer/HTTPServer.cpp
+++ b/src/HTTPServer/HTTPServer.cpp
@@ -29,6 +29,8 @@ class cDebugCallbacks :
{
virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override
{
+ UNUSED(a_Connection);
+
if (cHTTPFormParser::HasFormData(a_Request))
{
a_Request.SetUserData(new cHTTPFormParser(a_Request, *this));
@@ -38,6 +40,8 @@ class cDebugCallbacks :
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override
{
+ UNUSED(a_Connection);
+
cHTTPFormParser * FormParser = (cHTTPFormParser *)(a_Request.GetUserData());
if (FormParser != NULL)
{
diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h
index 24baf8c95..383abb4b6 100644
--- a/src/HTTPServer/HTTPServer.h
+++ b/src/HTTPServer/HTTPServer.h
@@ -37,6 +37,8 @@ public:
class cCallbacks
{
public:
+ virtual ~cCallbacks() {}
+
/** Called when a new request arrives over a connection and its headers have been parsed.
The request body needn't have arrived yet.
*/
@@ -50,7 +52,7 @@ public:
} ;
cHTTPServer(void);
- ~cHTTPServer();
+ virtual ~cHTTPServer();
/// Initializes the server on the specified ports
bool Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6);
diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h
index d853929ed..77695fe4a 100644
--- a/src/HTTPServer/MultipartParser.h
+++ b/src/HTTPServer/MultipartParser.h
@@ -22,6 +22,9 @@ public:
class cCallbacks
{
public:
+ // Force a virtual destructor in descendants:
+ virtual ~cCallbacks() {}
+
/// Called when a new part starts
virtual void OnPartStart(void) = 0;
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 7f434adfd..c7c089d5f 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -204,6 +204,12 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
return;
}
Grid->SetSlot(GridSlotNum, a_Item);
+
+ // Broadcast the Equipped Item, if the Slot is changed.
+ if ((Grid == &m_HotbarSlots) && (m_EquippedSlotNum == (a_SlotNum - invHotbarOffset)))
+ {
+ m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, a_Item, m_Owner.GetClientHandle());
+ }
}
diff --git a/src/Inventory.h b/src/Inventory.h
index fd2089a13..1ad7c4776 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -52,6 +52,8 @@ public:
cInventory(cPlayer & a_Owner);
+ virtual ~cInventory() {}
+
// tolua_begin
/// Removes all items from the entire inventory
diff --git a/src/Item.cpp b/src/Item.cpp
index 9170006b6..856b68be6 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -1,4 +1,4 @@
-
+
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Item.h"
@@ -139,6 +139,16 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["Lore"] = m_Lore;
}
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker;
+ a_OutValue["Trail"] = m_FireworkItem.m_HasTrail;
+ a_OutValue["Type"] = m_FireworkItem.m_Type;
+ a_OutValue["FlightTimeInTicks"] = m_FireworkItem.m_FlightTimeInTicks;
+ a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
+ a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
+ }
}
}
@@ -157,6 +167,16 @@ void cItem::FromJson(const Json::Value & a_Value)
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
m_CustomName = a_Value.get("Name", "").asString();
m_Lore = a_Value.get("Lore", "").asString();
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool();
+ m_FireworkItem.m_HasTrail = a_Value.get("Trail", false).asBool();
+ m_FireworkItem.m_Type = (NIBBLETYPE)a_Value.get("Type", 0).asInt();
+ m_FireworkItem.m_FlightTimeInTicks = (short)a_Value.get("FlightTimeInTicks", 0).asInt();
+ m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
+ m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
+ }
}
}
@@ -196,7 +216,7 @@ cItem * cItems::Get(int a_Idx)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently %d items. Returning a nil.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently " SIZE_T_FMT " items. Returning a nil.", a_Idx, size());
return NULL;
}
return &at(a_Idx);
@@ -210,7 +230,7 @@ void cItems::Set(int a_Idx, const cItem & a_Item)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
return;
}
at(a_Idx) = a_Item;
@@ -224,7 +244,7 @@ void cItems::Delete(int a_Idx)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently %d items. Ignoring.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Ignoring.", a_Idx, size());
return;
}
erase(begin() + a_Idx);
@@ -238,7 +258,7 @@ void cItems::Set(int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDama
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
return;
}
at(a_Idx) = cItem(a_ItemType, a_ItemCount, a_ItemDamage);
diff --git a/src/Item.h b/src/Item.h
index cc3b3c961..910ecb382 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -11,6 +11,7 @@
#include "Defines.h"
#include "Enchantments.h"
+#include "WorldStorage/FireworksSerializer.h"
@@ -38,7 +39,8 @@ public:
m_ItemCount(0),
m_ItemDamage(0),
m_CustomName(""),
- m_Lore("")
+ m_Lore(""),
+ m_FireworkItem()
{
}
@@ -57,7 +59,8 @@ public:
m_ItemDamage (a_ItemDamage),
m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
- m_Lore (a_Lore)
+ m_Lore (a_Lore),
+ m_FireworkItem()
{
if (!IsValidItem(m_ItemType))
{
@@ -77,7 +80,8 @@ public:
m_ItemDamage (a_CopyFrom.m_ItemDamage),
m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
- m_Lore (a_CopyFrom.m_Lore)
+ m_Lore (a_CopyFrom.m_Lore),
+ m_FireworkItem(a_CopyFrom.m_FireworkItem)
{
}
@@ -90,6 +94,7 @@ public:
m_Enchantments.Clear();
m_CustomName = "";
m_Lore = "";
+ m_FireworkItem.EmptyData();
}
@@ -115,7 +120,8 @@ public:
(m_ItemDamage == a_Item.m_ItemDamage) &&
(m_Enchantments == a_Item.m_Enchantments) &&
(m_CustomName == a_Item.m_CustomName) &&
- (m_Lore == a_Item.m_Lore)
+ (m_Lore == a_Item.m_Lore) &&
+ m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem)
);
}
@@ -177,6 +183,8 @@ public:
cEnchantments m_Enchantments;
AString m_CustomName;
AString m_Lore;
+
+ cFireworkItem m_FireworkItem;
};
// tolua_end
@@ -201,7 +209,7 @@ public:
void Add (const cItem & a_Item) {push_back(a_Item); }
void Delete(int a_Idx);
void Clear (void) {clear(); }
- int Size (void) {return size(); }
+ size_t Size (void) {return size(); }
void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage);
void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage)
diff --git a/src/ItemGrid.h b/src/ItemGrid.h
index b344e3daf..c34d5e9e2 100644
--- a/src/ItemGrid.h
+++ b/src/ItemGrid.h
@@ -20,11 +20,13 @@ class cItemGrid
public:
// tolua_end
- /// This class is used as a callback for when a slot changes
+ /** This class is used as a callback for when a slot changes */
class cListener
{
public:
- /// Called whenever a slot changes
+ virtual ~cListener() {}
+
+ /** Called whenever a slot changes */
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) = 0;
} ;
typedef std::vector<cListener *> cListeners;
@@ -38,12 +40,12 @@ public:
int GetHeight (void) const { return m_Height; }
int GetNumSlots(void) const { return m_NumSlots; }
- /// Converts XY coords into slot number; returns -1 on invalid coords
+ /** Converts XY coords into slot number; returns -1 on invalid coords */
int GetSlotNum(int a_X, int a_Y) const;
// tolua_end
- /// Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp
+ /** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */
void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const;
// tolua_begin
@@ -62,16 +64,16 @@ public:
void EmptySlot(int a_X, int a_Y);
void EmptySlot(int a_SlotNum);
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_SlotNum) const;
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_X, int a_Y) const;
- /// Sets all items as empty
+ /** Sets all items as empty */
void Clear(void);
- /// Returns number of items out of a_ItemStack that can fit in the storage
+ /** Returns number of items out of a_ItemStack that can fit in the storage */
int HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
/** Adds as many items out of a_ItemStack as can fit.
@@ -117,37 +119,37 @@ public:
*/
cItem RemoveOneItem(int a_X, int a_Y);
- /// Returns the number of items of type a_Item that are stored
+ /** Returns the number of items of type a_Item that are stored */
int HowManyItems(const cItem & a_Item);
- /// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
+ /** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */
bool HasItems(const cItem & a_ItemStack);
- /// Returns the index of the first empty slot; -1 if all full
+ /** Returns the index of the first empty slot; -1 if all full */
int GetFirstEmptySlot(void) const;
- /// Returns the index of the first non-empty slot; -1 if all empty
+ /** Returns the index of the first non-empty slot; -1 if all empty */
int GetFirstUsedSlot(void) const;
- /// Returns the index of the last empty slot; -1 if all full
+ /** Returns the index of the last empty slot; -1 if all full */
int GetLastEmptySlot(void) const;
- /// Returns the index of the last used slot; -1 if all empty
+ /** Returns the index of the last used slot; -1 if all empty */
int GetLastUsedSlot(void) const;
- /// Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextEmptySlot(int a_StartFrom) const;
- /// Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextUsedSlot(int a_StartFrom) const;
- /// Copies the contents into a cItems object; preserves the original a_Items contents
+ /** Copies the contents into a cItems object; preserves the original a_Items contents */
void CopyToItems(cItems & a_Items) const;
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_SlotNum, short a_Amount);
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_X, int a_Y, short a_Amount);
// tolua_end
@@ -159,10 +161,10 @@ public:
*/
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed);
- /// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
+ /** Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback! */
void AddListener(cListener & a_Listener);
- /// Removes a slot-change-callback. Must not be called from within the listener callback!
+ /** Removes a slot-change-callback. Must not be called from within the listener callback! */
void RemoveListener(cListener & a_Listener);
// tolua_begin
@@ -177,7 +179,7 @@ protected:
cCriticalSection m_CSListeners; ///< CS that guards the m_Listeners against multi-thread access
bool m_IsInTriggerListeners; ///< Set to true while TriggerListeners is running, to detect attempts to manipulate listener list while triggerring
- /// Calls all m_Listeners for the specified slot number
+ /** Calls all m_Listeners for the specified slot number */
void TriggerListeners(int a_SlotNum);
/** Adds up to a_Num items out of a_ItemStack, as many as can fit, in specified slot
diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h
index a28ec8e22..42f4ffc8f 100644
--- a/src/Items/ItemBoat.h
+++ b/src/Items/ItemBoat.h
@@ -39,12 +39,20 @@ public:
public cBlockTracer::cCallbacks
{
public:
- Vector3d Pos;
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ Vector3d m_Pos;
+ bool m_HasFound;
+
+ cCallbacks(void) :
+ m_HasFound(false)
{
- if (a_BlockType != E_BLOCK_AIR)
+ }
+
+ virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override
+ {
+ if (a_CBBlockType != E_BLOCK_AIR)
{
- Pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
+ m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ);
+ m_HasFound = true;
return true;
}
return false;
@@ -57,15 +65,15 @@ public:
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
- double x = Callbacks.Pos.x;
- double y = Callbacks.Pos.y;
- double z = Callbacks.Pos.z;
-
- if ((x == 0) && (y == 0) && (z == 0))
+ if (!Callbacks.m_HasFound)
{
return false;
}
+ double x = Callbacks.m_Pos.x;
+ double y = Callbacks.m_Pos.y;
+ double z = Callbacks.m_Pos.z;
+
cBoat * Boat = new cBoat(x + 0.5, y + 1, z + 0.5);
Boat->Initialize(a_World);
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 72cb8fa0a..68c89dd85 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -172,12 +172,12 @@ public:
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
- if (a_BlockMeta != 0) // Even if it was a water block it would not be a source.
- {
- return false;
- }
if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType))
{
+ if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source
+ {
+ return false;
+ }
m_HasHitFluid = true;
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ);
return true;
diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h
new file mode 100644
index 000000000..48e23ed59
--- /dev/null
+++ b/src/Items/ItemCake.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemCakeHandler :
+ public cItemHandler
+{
+public:
+ cItemCakeHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_CAKE;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index c10d13edc..337b3a83c 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -13,6 +13,7 @@
#include "ItemBow.h"
#include "ItemBrewingStand.h"
#include "ItemBucket.h"
+#include "ItemCake.h"
#include "ItemCauldron.h"
#include "ItemCloth.h"
#include "ItemComparator.h"
@@ -26,6 +27,7 @@
#include "ItemHoe.h"
#include "ItemLeaves.h"
#include "ItemLighter.h"
+#include "ItemLilypad.h"
#include "ItemMap.h"
#include "ItemMinecart.h"
#include "ItemNetherWart.h"
@@ -94,6 +96,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
// Single item per handler, alphabetically sorted:
case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType);
+ case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType);
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
@@ -101,16 +104,19 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler();
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
+ case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
case E_ITEM_EGG: return new cItemEggHandler();
case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
+ case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
+ case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
@@ -248,6 +254,14 @@ cItemHandler::cItemHandler(int a_ItemType)
bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
{
+ UNUSED(a_World);
+ UNUSED(a_Player);
+ UNUSED(a_Item);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_Dir);
+
return false;
}
@@ -257,6 +271,14 @@ bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem &
bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
{
+ UNUSED(a_World);
+ UNUSED(a_Player);
+ UNUSED(a_Item);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_Dir);
+
return false;
}
@@ -266,8 +288,10 @@ bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cI
void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ)
{
+ UNUSED(a_Item);
+
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(Block);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(Block);
if (a_Player->IsGameModeSurvival())
{
@@ -288,7 +312,9 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const
void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_Item)
{
-
+ UNUSED(a_World);
+ UNUSED(a_Player);
+ UNUSED(a_Item);
}
@@ -317,6 +343,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_BREWING_STAND: return 64;
case E_ITEM_BUCKET: return 16;
case E_ITEM_CARROT: return 64;
+ case E_ITEM_CAKE: return 1;
case E_ITEM_CAULDRON: return 64;
case E_ITEM_CLAY: return 64;
case E_ITEM_CLAY_BRICK: return 64;
@@ -461,6 +488,8 @@ bool cItemHandler::IsPlaceable(void)
bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
{
+ UNUSED(a_BlockType);
+
return false;
}
@@ -499,6 +528,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
+ UNUSED(a_Item);
+
FoodInfo Info = GetFoodInfo();
if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index ef3f37a7a..5b6c239cc 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -21,6 +21,9 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
+ // Force virtual destructor
+ virtual ~cItemHandler() {}
+
/// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
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);
diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h
index 74e987445..27e7dba35 100644
--- a/src/Items/ItemItemFrame.h
+++ b/src/Items/ItemItemFrame.h
@@ -34,7 +34,11 @@ public:
if (Block == E_BLOCK_AIR)
{
cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ);
- ItemFrame->Initialize(a_World);
+ if (!ItemFrame->Initialize(a_World))
+ {
+ delete ItemFrame;
+ return false;
+ }
if (!a_Player->IsGameModeCreative())
{
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
index cc7daeb08..32f49cab6 100644
--- a/src/Items/ItemLighter.h
+++ b/src/Items/ItemLighter.h
@@ -26,16 +26,35 @@ public:
return false;
}
- a_Player->UseEquippedItem();
+ if (!a_Player->IsGameModeCreative())
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_FLINT_AND_STEEL:
+ {
+ a_Player->UseEquippedItem();
+ break;
+ }
+ case E_ITEM_FIRE_CHARGE:
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unknown Lighter Item!");
+ }
+ }
+ }
switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
{
case E_BLOCK_TNT:
{
// Activate the TNT:
- a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
break;
}
default:
@@ -49,6 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
{
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
+ a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
break;
}
}
diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h
new file mode 100644
index 000000000..5a29abe94
--- /dev/null
+++ b/src/Items/ItemLilypad.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "ItemHandler.h"
+#include "../Entities/Player.h"
+#include "Vector3.h"
+#include "../LineBlockTracer.h"
+#include "BlockInfo.h"
+
+
+
+
+
+class cItemLilypadHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemLilypadHandler(BLOCKTYPE a_BlockType)
+ : cItemHandler(a_BlockType)
+ {
+
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return false; // Set as not placeable so OnItemUse is called
+ }
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ if (a_BlockFace > BLOCK_FACE_NONE)
+ {
+ // Clicked on the side of a submerged block; vanilla allows placement, so should we
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ return true;
+ }
+
+ class cCallbacks :
+ public cBlockTracer::cCallbacks
+ {
+ public:
+ cCallbacks(cWorld * a_World) :
+ m_HasHitFluid(false),
+ m_World(a_World)
+ {
+ }
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ {
+ if (IsBlockWater(a_BlockType))
+ {
+ if ((a_BlockMeta != 0) || (a_EntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged
+ {
+ return false;
+ }
+ a_EntryFace = BLOCK_FACE_YP; // Always place pad at top of water block
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace);
+ BLOCKTYPE Block = m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (
+ !IsBlockWater(Block) &&
+ cBlockInfo::FullyOccupiesVoxel(Block)
+ )
+ {
+ // Can't place lilypad on air/in another block!
+ return true;
+ }
+ m_HasHitFluid = true;
+ m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ);
+ return true;
+ }
+ return false;
+ }
+
+ Vector3i m_Pos;
+ bool m_HasHitFluid;
+ cWorld * m_World;
+
+ };
+
+ cCallbacks Callbacks(a_World);
+ cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks);
+ Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
+ Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
+
+ Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
+
+ if (Callbacks.m_HasHitFluid)
+ {
+ a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ return true;
+ }
+
+ return false;
+ }
+};
+
+
+
+
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index bcaa5635a..25500aeb9 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -1,4 +1,3 @@
-
// ItemMinecart.h
// Declares the various minecart ItemHandlers
@@ -72,6 +71,11 @@ public:
}
} // switch (m_ItemType)
Minecart->Initialize(a_World);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
return true;
}
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index bde7f0905..2a8e40daa 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -19,17 +19,13 @@ public:
{
switch(m_ItemType)
{
- case E_ITEM_WOODEN_PICKAXE:
- case E_ITEM_GOLD_PICKAXE:
- return 1;
- case E_ITEM_STONE_PICKAXE:
- return 2;
- case E_ITEM_IRON_PICKAXE:
- return 3;
- case E_ITEM_DIAMOND_PICKAXE:
- return 4;
- default:
- return 0;
+ case E_ITEM_WOODEN_PICKAXE: return 1;
+ case E_ITEM_GOLD_PICKAXE: return 1;
+ case E_ITEM_STONE_PICKAXE: return 2;
+ case E_ITEM_IRON_PICKAXE: return 3;
+ case E_ITEM_DIAMOND_PICKAXE: return 4;
+
+ default: return 0;
}
}
@@ -61,6 +57,10 @@ public:
return PickaxeLevel() >= 2;
}
+ case E_BLOCK_ANVIL:
+ case E_BLOCK_ENCHANTMENT_TABLE:
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_LIT_FURNACE:
case E_BLOCK_COAL_ORE:
case E_BLOCK_STONE:
case E_BLOCK_COBBLESTONE:
diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h
index 18c6b8615..274d905a5 100644
--- a/src/Items/ItemRedstoneDust.h
+++ b/src/Items/ItemRedstoneDust.h
@@ -27,7 +27,7 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- if (!g_BlockFullyOccupiesVoxel[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust
+ if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust
{
return false;
}
diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h
index b8f75f5ba..39d2776fa 100644
--- a/src/Items/ItemShears.h
+++ b/src/Items/ItemShears.h
@@ -28,10 +28,10 @@ public:
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (Block == E_BLOCK_LEAVES)
+ if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
{
cItems Drops;
- Drops.push_back(cItem(E_BLOCK_LEAVES, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
+ Drops.push_back(cItem(Block, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
@@ -49,6 +49,7 @@ public:
case E_BLOCK_COBWEB:
case E_BLOCK_VINES:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
return true;
}
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index 46049f961..c6a4e714e 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -35,7 +35,7 @@ public:
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
- a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+ a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
return true;
}
@@ -127,13 +127,13 @@ public:
return false;
}
+ a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
+
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
- a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0);
-
return true;
}
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 9c81d004d..302473d71 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -13,12 +13,6 @@
-/// If more than this many chunks are in the queue, a warning is printed to the log
-#define WARN_ON_QUEUE_SIZE 800
-
-
-
-
/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
class cReader :
@@ -391,7 +385,7 @@ void cLightingThread::PrepareBlockLight(void)
int idx = BaseZ + x;
for (int y = m_HeightMap[idx], Index = idx + y * BlocksPerYLayer; y >= 0; y--, Index -= BlocksPerYLayer)
{
- if (g_BlockLightValue[m_BlockTypes[Index]] == 0)
+ if (cBlockInfo::GetLightValue(m_BlockTypes[Index]) == 0)
{
continue;
}
@@ -401,7 +395,7 @@ void cLightingThread::PrepareBlockLight(void)
m_SeedIdx1[m_NumSeeds++] = Index;
// Light it up:
- m_BlockLight[Index] = g_BlockLightValue[m_BlockTypes[Index]];
+ m_BlockLight[Index] = cBlockInfo::GetLightValue(m_BlockTypes[Index]);
}
}
}
diff --git a/src/LightingThread.h b/src/LightingThread.h
index 72d561348..770ae809f 100644
--- a/src/LightingThread.h
+++ b/src/LightingThread.h
@@ -160,22 +160,20 @@ protected:
inline void PropagateLight(
NIBBLETYPE * a_Light,
- int a_SrcIdx, int a_DstIdx,
+ unsigned int a_SrcIdx, unsigned int a_DstIdx,
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
)
{
- ASSERT(a_SrcIdx >= 0);
- ASSERT(a_SrcIdx < (int)ARRAYCOUNT(m_SkyLight));
- ASSERT(a_DstIdx >= 0);
- ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes));
+ ASSERT(a_SrcIdx < ARRAYCOUNT(m_SkyLight));
+ ASSERT(a_DstIdx < ARRAYCOUNT(m_BlockTypes));
- if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]])
+ if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]))
{
// We're not offering more light than the dest block already has
return;
}
- a_Light[a_DstIdx] = a_Light[a_SrcIdx] - g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]];
+ a_Light[a_DstIdx] = a_Light[a_SrcIdx] - cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]);
if (!a_IsSeedOut[a_DstIdx])
{
a_IsSeedOut[a_DstIdx] = true;
diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp
index da1c7f2fd..f4f29e833 100644
--- a/src/LineBlockTracer.cpp
+++ b/src/LineBlockTracer.cpp
@@ -5,7 +5,7 @@
#include "Globals.h"
#include "LineBlockTracer.h"
-#include "Vector3d.h"
+#include "Vector3.h"
#include "World.h"
#include "Chunk.h"
diff --git a/src/LinearUpscale.h b/src/LinearUpscale.h
index b337b3219..0b04408cf 100644
--- a/src/LinearUpscale.h
+++ b/src/LinearUpscale.h
@@ -18,7 +18,7 @@ Therefore, there is no cpp file.
InPlace upscaling works on a single array and assumes that the values to work on have already
been interspersed into the array to the cell boundaries.
-Specifically, a_Array[x * a_AnchorStepX + y * a_AnchorStepY] contains the anchor value.
+Specifically, a_Array[x * AnchorStepX + y * AnchorStepY] contains the anchor value.
Regular upscaling takes two arrays and "moves" the input from src to dst; src is expected packed.
*/
@@ -29,46 +29,48 @@ Regular upscaling takes two arrays and "moves" the input from src to dst; src is
/**
Linearly interpolates values in the array between the equidistant anchor points (upscales).
Works in-place (input is already present at the correct output coords)
+Uses templates to make it possible for the compiler to further optimizer the loops
*/
-template<typename TYPE> void LinearUpscale2DArrayInPlace(
- TYPE * a_Array,
- int a_SizeX, int a_SizeY, // Dimensions of the array
- int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction
-)
+template<
+ int SizeX, int SizeY, // Dimensions of the array
+ int AnchorStepX, int AnchorStepY,
+ typename TYPE
+>
+void LinearUpscale2DArrayInPlace(TYPE * a_Array)
{
// First interpolate columns where the anchor points are:
- int LastYCell = a_SizeY - a_AnchorStepY;
- for (int y = 0; y < LastYCell; y += a_AnchorStepY)
+ int LastYCell = SizeY - AnchorStepY;
+ for (int y = 0; y < LastYCell; y += AnchorStepY)
{
- int Idx = a_SizeX * y;
- for (int x = 0; x < a_SizeX; x += a_AnchorStepX)
+ int Idx = SizeX * y;
+ for (int x = 0; x < SizeX; x += AnchorStepX)
{
TYPE StartValue = a_Array[Idx];
- TYPE EndValue = a_Array[Idx + a_SizeX * a_AnchorStepY];
+ TYPE EndValue = a_Array[Idx + SizeX * AnchorStepY];
TYPE Diff = EndValue - StartValue;
- for (int CellY = 1; CellY < a_AnchorStepY; CellY++)
+ for (int CellY = 1; CellY < AnchorStepY; CellY++)
{
- a_Array[Idx + a_SizeX * CellY] = StartValue + Diff * CellY / a_AnchorStepY;
+ a_Array[Idx + SizeX * CellY] = StartValue + Diff * CellY / AnchorStepY;
} // for CellY
- Idx += a_AnchorStepX;
+ Idx += AnchorStepX;
} // for x
} // for y
// Now interpolate in rows, each row has values in the anchor columns
- int LastXCell = a_SizeX - a_AnchorStepX;
- for (int y = 0; y < a_SizeY; y++)
+ int LastXCell = SizeX - AnchorStepX;
+ for (int y = 0; y < SizeY; y++)
{
- int Idx = a_SizeX * y;
- for (int x = 0; x < LastXCell; x += a_AnchorStepX)
+ int Idx = SizeX * y;
+ for (int x = 0; x < LastXCell; x += AnchorStepX)
{
TYPE StartValue = a_Array[Idx];
- TYPE EndValue = a_Array[Idx + a_AnchorStepX];
+ TYPE EndValue = a_Array[Idx + AnchorStepX];
TYPE Diff = EndValue - StartValue;
- for (int CellX = 1; CellX < a_AnchorStepX; CellX++)
+ for (int CellX = 1; CellX < AnchorStepX; CellX++)
{
- a_Array[Idx + CellX] = StartValue + CellX * Diff / a_AnchorStepX;
+ a_Array[Idx + CellX] = StartValue + CellX * Diff / AnchorStepX;
} // for CellY
- Idx += a_AnchorStepX;
+ Idx += AnchorStepX;
}
}
}
diff --git a/src/Log.cpp b/src/Log.cpp
index 1ea327d5d..a7be04b1a 100644
--- a/src/Log.cpp
+++ b/src/Log.cpp
@@ -118,7 +118,7 @@ void cLog::Log(const char * a_Format, va_list argList)
AString Line;
#ifdef _DEBUG
- Printf(Line, "[%04x|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
+ Printf(Line, "[%04lx|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
#else
Printf(Line, "[%02d:%02d:%02d] %s", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
#endif
diff --git a/src/Log.h b/src/Log.h
index cba248dae..d6a406154 100644
--- a/src/Log.h
+++ b/src/Log.h
@@ -14,8 +14,8 @@ private:
public:
cLog(const AString & a_FileName);
~cLog();
- void Log(const char * a_Format, va_list argList);
- void Log(const char * a_Format, ...);
+ void Log(const char * a_Format, va_list argList) FORMATSTRING(2, 0);
+ void Log(const char * a_Format, ...) FORMATSTRING(2, 3);
// tolua_begin
void SimpleLog(const char * a_String);
void OpenLog(const char * a_FileName);
diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp
index 4f3e5dc0f..80fa7b173 100644
--- a/src/MCLogger.cpp
+++ b/src/MCLogger.cpp
@@ -93,25 +93,30 @@ void cMCLogger::InitLog(const AString & a_FileName)
-void cMCLogger::LogSimple(const char* a_Text, int a_LogType /* = 0 */ )
+void cMCLogger::LogSimple(const char * a_Text, eLogLevel a_LogLevel)
{
- switch( a_LogType )
+ switch (a_LogLevel)
{
- case 0:
+ case llRegular:
+ {
LOG("%s", a_Text);
break;
- case 1:
+ }
+ case llInfo:
+ {
LOGINFO("%s", a_Text);
break;
- case 2:
+ }
+ case llWarning:
+ {
LOGWARN("%s", a_Text);
break;
- case 3:
+ }
+ case llError:
+ {
LOGERROR("%s", a_Text);
break;
- default:
- LOG("(#%d#: %s", a_LogType, a_Text);
- break;
+ }
}
}
diff --git a/src/MCLogger.h b/src/MCLogger.h
index c949a4cdf..c0150c124 100644
--- a/src/MCLogger.h
+++ b/src/MCLogger.h
@@ -10,25 +10,36 @@ class cLog;
-class cMCLogger // tolua_export
-{ // tolua_export
-public: // tolua_export
- /// Creates a logger with the default filename, "logs/LOG_<timestamp>.log"
+// tolua_begin
+class cMCLogger
+{
+public:
+ enum eLogLevel
+ {
+ llRegular,
+ llInfo,
+ llWarning,
+ llError,
+ };
+ // tolua_end
+
+ /** Creates a logger with the default filename, "logs/LOG_<timestamp>.log" */
cMCLogger(void);
- /// Creates a logger with the specified filename inside "logs" folder
+ /** Creates a logger with the specified filename inside "logs" folder */
cMCLogger(const AString & a_FileName); // tolua_export
~cMCLogger(); // tolua_export
- void Log(const char* a_Format, va_list a_ArgList);
- void Info(const char* a_Format, va_list a_ArgList);
- void Warn(const char* a_Format, va_list a_ArgList);
- void Error(const char* a_Format, va_list a_ArgList);
+ void Log (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Info (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Warn (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Error(const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
- void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export
+ /** Logs the simple text message at the specified log level. */
+ void LogSimple(const char * a_Text, eLogLevel a_LogLevel = llRegular); // tolua_export
- static cMCLogger* GetInstance();
+ static cMCLogger * GetInstance();
private:
enum eColorScheme
{
@@ -57,10 +68,10 @@ private:
-extern void LOG(const char* a_Format, ...);
-extern void LOGINFO(const char* a_Format, ...);
-extern void LOGWARN(const char* a_Format, ...);
-extern void LOGERROR(const char* a_Format, ...);
+extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
diff --git a/src/Map.cpp b/src/Map.cpp
index 2d8f57168..79370b097 100644
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -243,7 +243,7 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
{
for (unsigned int Z = m_RelZ; Z < m_RelZ + PixelWidth; ++Z)
{
- unsigned int WaterDepth = 0;
+ // unsigned int WaterDepth = 0;
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
NIBBLETYPE TargetMeta = 0;
@@ -261,12 +261,14 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
continue;
}
// TODO 2014-02-22 xdot: Check if block is liquid
+ /*
else if (false)
{
--Height;
++WaterDepth;
continue;
}
+ */
break;
}
diff --git a/src/Map.h b/src/Map.h
index a313d5431..ee7c537b1 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -64,7 +64,7 @@ public:
unsigned int GetPixelX(void) const { return m_PixelX; }
unsigned int GetPixelZ(void) const { return m_PixelZ; }
- int GetRot(void) const { return m_Rot; }
+ unsigned int GetRot(void) const { return m_Rot; }
eType GetType(void) const { return m_Type; }
diff --git a/src/Matrix4.h b/src/Matrix4.h
new file mode 100644
index 000000000..456677f0f
--- /dev/null
+++ b/src/Matrix4.h
@@ -0,0 +1,224 @@
+
+#pragma once
+
+
+
+#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
+#include <math.h>
+
+
+
+
+
+template <typename T>
+// tolua_begin
+class Matrix4
+{
+
+ TOLUA_TEMPLATE_BIND((T, float, double))
+
+ // tolua_end
+
+public:
+
+ T cell[16];
+
+ // tolua_begin
+
+ inline Matrix4(void)
+ {
+ Identity();
+ }
+
+ inline Matrix4(const Matrix4 & a_Rhs)
+ {
+ *this = a_Rhs;
+ }
+
+ inline Matrix4 & operator = (const Matrix4 & a_Rhs)
+ {
+ for (unsigned int i = 0; i < 16; ++i)
+ {
+ cell[i] = a_Rhs.cell[i];
+ }
+ return *this;
+ }
+
+ inline T & operator [] (int a_N)
+ {
+ ASSERT(a_N < 16);
+ return cell[a_N];
+ }
+
+ inline void Identity()
+ {
+ cell[1] = cell[2] = cell[3] = cell[4] = 0;
+ cell[6] = cell[7] = cell[8] = cell[9] = 0;
+ cell[11] = cell[12] = cell[13] = cell[14] = 0;
+
+ cell[0] = cell[5] = cell[10] = cell[15] = 1;
+ }
+
+ inline void Init(const Vector3<T> & a_Pos, T a_RX, T a_RY, T a_RZ)
+ {
+ Matrix4<T> t;
+ t.RotateX(a_RZ);
+ RotateY(a_RY);
+ Concatenate(t);
+ t.RotateZ(a_RX);
+ Concatenate(t);
+ Translate(a_Pos);
+ }
+
+ inline void RotateX(T a_RX)
+ {
+ T sx = (T) sin(a_RX * M_PI / 180);
+ T cx = (T) cos(a_RX * M_PI / 180);
+
+ Identity();
+
+ cell[5] = cx; cell[6] = sx;
+ cell[9] = -sx; cell[10] = cx;
+ }
+
+ inline void RotateY(T a_RY)
+ {
+ T sy = (T) sin(a_RY * M_PI / 180);
+ T cy = (T) cos(a_RY * M_PI / 180);
+
+ Identity();
+
+ cell[0] = cy; cell[2] = -sy;
+ cell[8] = sy; cell[10] = cy;
+ }
+
+ inline void RotateZ(T a_RZ)
+ {
+ T sz = (T) sin(a_RZ * M_PI / 180);
+ T cz = (T) cos(a_RZ * M_PI / 180);
+
+ Identity();
+
+ cell[0] = cz; cell[1] = sz;
+ cell[4] = -sz; cell[5] = cz;
+ }
+
+ inline void Translate(const Vector3<T> & a_Pos)
+ {
+ cell[3] += a_Pos.x;
+ cell[7] += a_Pos.y;
+ cell[11] += a_Pos.z;
+ }
+
+ inline void SetTranslation(const Vector3<T> & a_Pos)
+ {
+ cell[3] = a_Pos.x;
+ cell[7] = a_Pos.y;
+ cell[11] = a_Pos.z;
+ }
+
+ inline void Concatenate(const Matrix4 & m2)
+ {
+ Matrix4 res;
+
+ for (unsigned int c = 0; c < 4; ++c)
+ {
+ for (unsigned int r = 0; r < 4; ++r)
+ {
+ res.cell[r * 4 + c] = (
+ cell[r * 4 + 0] * m2.cell[c + 0] +
+ cell[r * 4 + 1] * m2.cell[c + 4] +
+ cell[r * 4 + 2] * m2.cell[c + 8] +
+ cell[r * 4 + 3] * m2.cell[c + 12]
+ );
+ }
+ }
+
+ *this = res;
+ }
+
+ inline Vector3<T> Transform(const Vector3<T> & v) const
+ {
+ T x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
+ T y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
+ T z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
+
+ return Vector3<T>(x, y, z);
+ }
+
+ inline void Invert(void)
+ {
+ Matrix4 t;
+
+ T tx = -cell[3];
+ T ty = -cell[7];
+ T tz = -cell[11];
+
+ for (unsigned int h = 0; h < 3; ++h)
+ {
+ for (unsigned int v = 0; v < 3; ++v)
+ {
+ t.cell[h + v * 4] = cell[v + h * 4];
+ }
+ }
+
+ for (unsigned int i = 0; i < 11; ++i)
+ {
+ cell[i] = t.cell[i];
+ }
+
+ cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
+ cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
+ cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
+ }
+
+ inline Vector3<T> GetXColumn(void) const
+ {
+ return Vector3<T>(cell[0], cell[1], cell[2]);
+ }
+
+ inline Vector3<T> GetYColumn(void) const
+ {
+ return Vector3<T>(cell[4], cell[5], cell[6]);
+ }
+
+ inline Vector3<T> GetZColumn(void) const
+ {
+ return Vector3<T>(cell[8], cell[9], cell[10]);
+ }
+
+ inline void SetXColumn(const Vector3<T> & a_X)
+ {
+ cell[0] = a_X.x;
+ cell[1] = a_X.y;
+ cell[2] = a_X.z;
+ }
+
+ inline void SetYColumn(const Vector3<T> & a_Y)
+ {
+ cell[4] = a_Y.x;
+ cell[5] = a_Y.y;
+ cell[6] = a_Y.z;
+ }
+
+ inline void SetZColumn(const Vector3<T> & a_Z)
+ {
+ cell[8] = a_Z.x;
+ cell[9] = a_Z.y;
+ cell[10] = a_Z.z;
+ }
+};
+// tolua_end
+
+
+
+
+// tolua_begin
+typedef Matrix4<double> Matrix4d;
+typedef Matrix4<float> Matrix4f;
+// tolua_end
+
+
+
+
+
diff --git a/src/Matrix4f.cpp b/src/Matrix4f.cpp
deleted file mode 100644
index d0a407a99..000000000
--- a/src/Matrix4f.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-// _X: empty file??
diff --git a/src/Matrix4f.h b/src/Matrix4f.h
deleted file mode 100644
index 249c92f5f..000000000
--- a/src/Matrix4f.h
+++ /dev/null
@@ -1,225 +0,0 @@
-#pragma once
-
-#define _USE_MATH_DEFINES
-#include <math.h>
-#include "Vector3f.h"
-
-class Matrix4f
-{
-public:
- enum
- {
- TX=3,
- TY=7,
- TZ=11,
- D0=0, D1=5, D2=10, D3=15,
- SX=D0, SY=D1, SZ=D2,
- W=D3
- };
- Matrix4f() { Identity(); }
- float& operator [] ( int a_N ) { return cell[a_N]; }
- void Identity()
- {
- cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
- cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
- cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
- }
- void Init( Vector3f a_Pos, float a_RX, float a_RY, float a_RZ )
- {
- Matrix4f t;
- t.RotateX( a_RZ );
- RotateY( a_RY );
- Concatenate( t );
- t.RotateZ( a_RX );
- Concatenate( t );
- Translate( a_Pos );
- }
- void RotateX( float a_RX )
- {
- float sx = (float)sin( a_RX * M_PI / 180 );
- float cx = (float)cos( a_RX * M_PI / 180 );
- Identity();
- cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
- }
- void RotateY( float a_RY )
- {
- float sy = (float)sin( a_RY * M_PI / 180 );
- float cy = (float)cos( a_RY * M_PI / 180 );
- Identity ();
- cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
- }
- void RotateZ( float a_RZ )
- {
- float sz = (float)sin( a_RZ * M_PI / 180 );
- float cz = (float)cos( a_RZ * M_PI / 180 );
- Identity ();
- cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
- }
- void Translate( Vector3f a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
- void SetTranslation( Vector3f a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
- void Concatenate( const Matrix4f& m2 )
- {
- Matrix4f res;
- int c;
- for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
- res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
- cell[r * 4 + 1] * m2.cell[c + 4] +
- cell[r * 4 + 2] * m2.cell[c + 8] +
- cell[r * 4 + 3] * m2.cell[c + 12];
- for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
- }
- Vector3f Transform( const Vector3f& v ) const
- {
- float x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
- float y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
- float z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
- return Vector3f( x, y, z );
- }
- void Invert()
- {
- Matrix4f t;
- int h, i;
- float tx = -cell[3], ty = -cell[7], tz = -cell[11];
- for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
- for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
- cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
- cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
- cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
- }
- Vector3f GetXColumn() { return Vector3f( cell[0], cell[1], cell[2] ); }
- Vector3f GetYColumn() { return Vector3f( cell[4], cell[5], cell[6] ); }
- Vector3f GetZColumn() { return Vector3f( cell[8], cell[9], cell[10] ); }
- void SetXColumn( const Vector3f & a_X )
- {
- cell[0] = a_X.x;
- cell[1] = a_X.y;
- cell[2] = a_X.z;
- }
- void SetYColumn( const Vector3f & a_Y )
- {
- cell[4] = a_Y.x;
- cell[5] = a_Y.y;
- cell[6] = a_Y.z;
- }
- void SetZColumn( const Vector3f & a_Z )
- {
- cell[8] = a_Z.x;
- cell[9] = a_Z.y;
- cell[10] = a_Z.z;
- }
- float cell[16];
-};
-
-
-
-
-
-class Matrix4d
-{
-public:
- enum
- {
- TX=3,
- TY=7,
- TZ=11,
- D0=0, D1=5, D2=10, D3=15,
- SX=D0, SY=D1, SZ=D2,
- W=D3
- };
- Matrix4d() { Identity(); }
- double& operator [] ( int a_N ) { return cell[a_N]; }
- void Identity()
- {
- cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
- cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
- cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
- }
- void Init( Vector3f a_Pos, double a_RX, double a_RY, double a_RZ )
- {
- Matrix4d t;
- t.RotateX( a_RZ );
- RotateY( a_RY );
- Concatenate( t );
- t.RotateZ( a_RX );
- Concatenate( t );
- Translate( a_Pos );
- }
- void RotateX( double a_RX )
- {
- double sx = (double)sin( a_RX * M_PI / 180 );
- double cx = (double)cos( a_RX * M_PI / 180 );
- Identity();
- cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
- }
- void RotateY( double a_RY )
- {
- double sy = (double)sin( a_RY * M_PI / 180 );
- double cy = (double)cos( a_RY * M_PI / 180 );
- Identity ();
- cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
- }
- void RotateZ( double a_RZ )
- {
- double sz = (double)sin( a_RZ * M_PI / 180 );
- double cz = (double)cos( a_RZ * M_PI / 180 );
- Identity ();
- cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
- }
- void Translate( Vector3d a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
- void SetTranslation( Vector3d a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
- void Concatenate( const Matrix4d & m2 )
- {
- Matrix4d res;
- int c;
- for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
- res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
- cell[r * 4 + 1] * m2.cell[c + 4] +
- cell[r * 4 + 2] * m2.cell[c + 8] +
- cell[r * 4 + 3] * m2.cell[c + 12];
- for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
- }
- Vector3d Transform( const Vector3d & v ) const
- {
- double x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
- double y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
- double z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
- return Vector3d( x, y, z );
- }
- void Invert()
- {
- Matrix4d t;
- int h, i;
- double tx = -cell[3], ty = -cell[7], tz = -cell[11];
- for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
- for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
- cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
- cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
- cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
- }
- Vector3d GetXColumn() { return Vector3d( cell[0], cell[1], cell[2] ); }
- Vector3d GetYColumn() { return Vector3d( cell[4], cell[5], cell[6] ); }
- Vector3d GetZColumn() { return Vector3d( cell[8], cell[9], cell[10] ); }
- void SetXColumn( const Vector3d & a_X )
- {
- cell[0] = a_X.x;
- cell[1] = a_X.y;
- cell[2] = a_X.z;
- }
- void SetYColumn( const Vector3d & a_Y )
- {
- cell[4] = a_Y.x;
- cell[5] = a_Y.y;
- cell[6] = a_Y.z;
- }
- void SetZColumn( const Vector3d & a_Z )
- {
- cell[8] = a_Z.x;
- cell[9] = a_Z.y;
- cell[10] = a_Z.z;
- }
- double cell[16];
-} ;
-
-
-
-
diff --git a/src/MersenneTwister.h b/src/MersenneTwister.h
index f4c7b0699..759b8a1ae 100644
--- a/src/MersenneTwister.h
+++ b/src/MersenneTwister.h
@@ -62,7 +62,7 @@
class MTRand {
// Data
public:
- typedef long uint32; // unsigned integer type, at least 32 bits
+ typedef UInt32 uint32; // unsigned integer type, at least 32 bits
enum { N = 624 }; // length of state vector
enum { SAVE = N + 1 }; // length of array for save()
@@ -72,7 +72,7 @@ protected:
uint32 state[N]; // internal state
uint32 *pNext; // next value to get from state
- int left; // number of values left before reload needed
+ uint32 left; // number of values left before reload needed
// Methods
public:
@@ -164,7 +164,7 @@ inline void MTRand::initialize( const uint32 seed )
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
uint32 *s = state;
uint32 *r = state;
- int i = 1;
+ uint32 i = 1;
*s++ = seed & 0xffffffffUL;
for( ; i < N; ++i )
{
@@ -205,9 +205,9 @@ inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
// in each element are discarded.
// Just call seed() if you want to get array from /dev/urandom
initialize(19650218UL);
- int i = 1;
+ uint32 i = 1;
uint32 j = 0;
- int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
+ uint32 k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
for( ; k; --k )
{
state[i] =
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index c86268e63..05da5d01c 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -129,6 +129,11 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock))
{
+ if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0))
+ {
+ return false;
+ }
+
NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
NIBBLETYPE SkyLight = a_Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
BLOCKTYPE BlockAbove = a_Chunk->GetBlock(a_RelX, a_RelY + 1, a_RelZ);
@@ -145,7 +150,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
case cMonster::mtBat:
{
- return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && (!g_BlockTransparent[BlockAbove]);
+ return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && !cBlockInfo::IsTransparent(BlockAbove);
}
case cMonster::mtChicken:
@@ -157,7 +162,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return (
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
- (!g_BlockTransparent[BlockBelow]) &&
+ (!cBlockInfo::IsTransparent(BlockBelow)) &&
(BlockBelow == E_BLOCK_GRASS) &&
(SkyLight >= 9)
);
@@ -169,7 +174,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(
- (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)
+ (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) &&
(a_RelY >= 62) &&
(m_Random.NextInt(3, a_Biome) != 0)
@@ -188,7 +193,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(BlockTop == E_BLOCK_AIR) &&
- (!g_BlockTransparent[BlockBelow]) &&
+ (!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) &&
(BlockLight <= 7)
);
@@ -200,7 +205,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
case cMonster::mtSpider:
{
bool CanSpawn = true;
- bool HaveFloor = false;
+ bool HasFloor = false;
for (int x = 0; x < 2; ++x)
{
for(int z = 0; z < 2; ++z)
@@ -211,16 +216,16 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
{
return false;
}
- HaveFloor = (
- HaveFloor ||
+ HasFloor = (
+ HasFloor ||
(
a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock) &&
- !g_BlockTransparent[TargetBlock]
+ !cBlockInfo::IsTransparent(TargetBlock)
)
);
}
}
- return CanSpawn && HaveFloor && (SkyLight <= 7) && (BlockLight <= 7);
+ return CanSpawn && HasFloor && (SkyLight <= 7) && (BlockLight <= 7);
}
case cMonster::mtCreeper:
@@ -230,7 +235,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return (
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
- (!g_BlockTransparent[BlockBelow]) &&
+ (!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) &&
(BlockLight <= 7) &&
(m_Random.NextInt(2, a_Biome) == 0)
@@ -242,7 +247,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return (
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
- (!g_BlockTransparent[BlockBelow]) &&
+ (!cBlockInfo::IsTransparent(BlockBelow)) &&
(
(a_RelY <= 40) || (a_Biome == biSwampland)
)
@@ -255,7 +260,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return (
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
- (!g_BlockTransparent[BlockBelow]) &&
+ (!cBlockInfo::IsTransparent(BlockBelow)) &&
(m_Random.NextInt(20, a_Biome) == 0)
);
}
diff --git a/src/Mobs/Bat.cpp b/src/Mobs/Bat.cpp
index b9c82996b..1417ddd9e 100644
--- a/src/Mobs/Bat.cpp
+++ b/src/Mobs/Bat.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Bat.h"
-#include "../Vector3d.h"
+#include "../Vector3.h"
#include "../Chunk.h"
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index ac42cf40b..84ff8929b 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -53,4 +53,4 @@ void cBlaze::Attack(float a_Dt)
m_AttackInterval = 0.0;
// ToDo: Shoot 3 fireballs instead of 1.
}
-} \ No newline at end of file
+}
diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h
index cdb3a1306..5970451c7 100644
--- a/src/Mobs/Blaze.h
+++ b/src/Mobs/Blaze.h
@@ -20,7 +20,3 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Attack(float a_Dt) override;
} ;
-
-
-
-
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index 40ee20e44..3471b4cf1 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -4,6 +4,7 @@
#include "Creeper.h"
#include "../World.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/Player.h"
@@ -13,6 +14,7 @@ cCreeper::cCreeper(void) :
super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
m_bIsBlowing(false),
m_bIsCharged(false),
+ m_BurnedWithFlintAndSteel(false),
m_ExplodingTimer(0)
{
}
@@ -25,12 +27,25 @@ void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- if (!ReachedFinalDestination())
+ if (!ReachedFinalDestination() && !m_BurnedWithFlintAndSteel)
{
m_ExplodingTimer = 0;
m_bIsBlowing = false;
m_World->BroadcastEntityMetadata(*this);
}
+ else
+ {
+ if (m_bIsBlowing)
+ {
+ m_ExplodingTimer += 1;
+ }
+
+ if (m_ExplodingTimer == 30)
+ {
+ m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
+ Destroy();
+ }
+ }
}
@@ -80,22 +95,30 @@ void cCreeper::Attack(float a_Dt)
{
UNUSED(a_Dt);
- m_ExplodingTimer += 1;
-
if (!m_bIsBlowing)
{
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
}
-
- if (m_ExplodingTimer == 20)
- {
- m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
- Destroy();
- }
}
+
+void cCreeper::OnRightClicked(cPlayer & a_Player)
+{
+ if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_FLINT_AND_STEEL))
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.UseEquippedItem();
+ }
+ m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_bIsBlowing = true;
+ m_World->BroadcastEntityMetadata(*this);
+ m_BurnedWithFlintAndSteel = true;
+ }
+}
+
diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h
index 0f71e5ad2..9abca369b 100644
--- a/src/Mobs/Creeper.h
+++ b/src/Mobs/Creeper.h
@@ -21,13 +21,14 @@ public:
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Attack(float a_Dt) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
bool IsBlowing(void) const {return m_bIsBlowing; }
bool IsCharged(void) const {return m_bIsCharged; }
private:
- bool m_bIsBlowing, m_bIsCharged;
+ bool m_bIsBlowing, m_bIsCharged, m_BurnedWithFlintAndSteel;
int m_ExplodingTimer;
} ;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index ac9137ccd..aa6071515 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -82,11 +82,11 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_AttackRange(2)
, m_AttackInterval(0)
, m_SightDistance(25)
- , m_DropChanceWeapon(0.085)
- , m_DropChanceHelmet(0.085)
- , m_DropChanceChestplate(0.085)
- , m_DropChanceLeggings(0.085)
- , m_DropChanceBoots(0.085)
+ , m_DropChanceWeapon(0.085f)
+ , m_DropChanceHelmet(0.085f)
+ , m_DropChanceChestplate(0.085f)
+ , m_DropChanceLeggings(0.085f)
+ , m_DropChanceBoots(0.085f)
, m_CanPickUpLoot(true)
, m_BurnsInDaylight(false)
{
@@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
void cMonster::TickPathFinding()
{
- int PosX = (int)floor(GetPosX());
- int PosY = (int)floor(GetPosY());
- int PosZ = (int)floor(GetPosZ());
+ const int PosX = (int)floor(GetPosX());
+ const int PosY = (int)floor(GetPosY());
+ const int PosZ = (int)floor(GetPosZ());
m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
@@ -130,14 +130,16 @@ void cMonster::TickPathFinding()
{ 0, 1},
{ 0,-1},
} ;
+
+ 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();
+ return;
+ }
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{
- if ((gCrossCoords[i].x + PosX == PosX) && (gCrossCoords[i].z + PosZ == PosZ))
- {
- continue;
- }
-
if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
{
continue;
@@ -148,11 +150,11 @@ void cMonster::TickPathFinding()
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ);
- if ((!g_BlockIsSolid[BlockAtY]) && (!g_BlockIsSolid[BlockAtYP]) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
+ if ((!cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
{
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
}
- else if ((g_BlockIsSolid[BlockAtY]) && (!g_BlockIsSolid[BlockAtYP]) && (!g_BlockIsSolid[BlockAtYPP]) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
+ else if ((cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!cBlockInfo::IsSolid(BlockAtYPP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
{
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
}
@@ -416,9 +418,9 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
else if (PosY > cChunkDef::Height)
PosY = cChunkDef::Height;
- if (!g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))])
+ if (!cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))))
{
- while (!g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))] && (PosY > 0))
+ while (!cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY > 0))
{
PosY--;
}
@@ -427,7 +429,7 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
}
else
{
- while (g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))] && (PosY < cChunkDef::Height))
+ while (cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY < cChunkDef::Height))
{
PosY++;
}
@@ -758,6 +760,7 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
case mtSquid: return mfWater;
case mtVillager: return mfPassive;
case mtWitch: return mfHostile;
+ case mtWither: return mfHostile;
case mtWolf: return mfHostile;
case mtZombie: return mfHostile;
case mtZombiePigman: return mfHostile;
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 4761103e5..c64360153 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -68,17 +68,28 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{
- // The sheep should not move when he's eating so only handle the physics.
+ super::Tick(a_Dt, a_Chunk);
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT - 1;
+ int PosZ = POSZ_TOINT;
+
+ if ((PosY <= 0) || (PosY > cChunkDef::Height))
+ {
+ return;
+ }
+
if (m_TimeToStopEating > 0)
{
- HandlePhysics(a_Dt, a_Chunk);
+ m_bMovingToDestination = false; // The sheep should not move when he's eating
m_TimeToStopEating--;
+
if (m_TimeToStopEating == 0)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
{
- // The sheep ate the grass so we change it to dirt.
- m_World->SetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ(), E_BLOCK_DIRT, 0);
+ // The sheep ate the grass so we change it to dirt
+ m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
+ GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
m_IsSheared = false;
m_World->BroadcastEntityMetadata(*this);
}
@@ -86,12 +97,11 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
else
{
- super::Tick(a_Dt, a_Chunk);
if (m_World->GetTickRandomNumber(600) == 1)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
{
- m_World->BroadcastEntityStatus(*this, 10);
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
m_TimeToStopEating = 40;
}
}
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 47fcdbb26..1685f40c5 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -88,4 +88,4 @@ void cSkeleton::Attack(float a_Dt)
m_World->BroadcastSpawnEntity(*Arrow);
m_AttackInterval = 0.0;
}
-} \ No newline at end of file
+}
diff --git a/src/Mobs/SnowGolem.cpp b/src/Mobs/SnowGolem.cpp
index 67e3a3bb8..c1979a495 100644
--- a/src/Mobs/SnowGolem.cpp
+++ b/src/Mobs/SnowGolem.cpp
@@ -38,7 +38,7 @@ void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk)
{
BLOCKTYPE BlockBelow = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()) - 1, (int) floor(GetPosZ()));
BLOCKTYPE Block = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()));
- if (Block == E_BLOCK_AIR && g_BlockIsSolid[BlockBelow])
+ if (Block == E_BLOCK_AIR && cBlockInfo::IsSolid(BlockBelow))
{
m_World->SetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()), E_BLOCK_SNOW, 0);
}
diff --git a/src/Mobs/Squid.cpp b/src/Mobs/Squid.cpp
index ba9171b39..bd0e141a0 100644
--- a/src/Mobs/Squid.cpp
+++ b/src/Mobs/Squid.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Squid.h"
-#include "../Vector3d.h"
+#include "../Vector3.h"
#include "../Chunk.h"
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 09a6e2d09..bbd8d6aaa 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -150,7 +150,7 @@ void cVillager::HandleFarmerTryHarvestCrops()
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7)
{
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(CropBlock);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock);
cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World);
Handler->DropBlock(ChunkInterface, *m_World, PluginInterface, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index b99ae876f..5bba4d4ba 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -29,7 +29,7 @@ public:
CLASS_PROTODEF(cVillager);
- // Override functions
+ // cEntity overrides
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index c46e0beab..8f5d28b68 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -2,14 +2,90 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Wither.h"
+#include "../World.h"
cWither::cWither(void) :
- super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0)
+ super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
+ m_InvulnerableTicks(220)
{
+ SetMaxHealth(300);
+}
+
+
+
+
+
+bool cWither::IsArmored(void) const
+{
+ return GetHealth() <= (GetMaxHealth() / 2);
+}
+
+
+
+
+
+bool cWither::Initialize(cWorld * a_World)
+{
+ // Set health before BroadcastSpawnEntity()
+ SetHealth(GetMaxHealth() / 3);
+
+ return super::Initialize(a_World);
+}
+
+
+
+
+
+void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (a_TDI.DamageType == dtDrowning)
+ {
+ return;
+ }
+
+ if (m_InvulnerableTicks > 0)
+ {
+ return;
+ }
+
+ if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
+ {
+ return;
+ }
+
+ super::DoTakeDamage(a_TDI);
+}
+
+
+
+
+
+void cWither::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_InvulnerableTicks > 0)
+ {
+ unsigned int NewTicks = m_InvulnerableTicks - 1;
+
+ if (NewTicks == 0)
+ {
+ m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
+ }
+
+ m_InvulnerableTicks = NewTicks;
+
+ if ((NewTicks % 10) == 0)
+ {
+ Heal(10);
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
}
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index 56effc6bb..bc78bfaad 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -16,8 +16,25 @@ public:
cWither(void);
CLASS_PROTODEF(cWither);
+
+ unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
+
+ void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
+
+ /** Returns whether the wither is invulnerable to arrows. */
+ bool IsArmored(void) const;
+ // cEntity overrides
+ virtual bool Initialize(cWorld * a_World) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
+ unsigned int m_InvulnerableTicks;
+
} ;
diff --git a/src/Noise.cpp b/src/Noise.cpp
index 5f23a47f9..a97ea70c6 100644
--- a/src/Noise.cpp
+++ b/src/Noise.cpp
@@ -3,14 +3,6 @@
#include "Noise.h"
-
-
-
-
-#if NOISE_USE_SSE
- #include <smmintrin.h> //_mm_mul_epi32
-#endif
-
#define FAST_FLOOR(x) (((x) < 0) ? (((int)x) - 1) : ((int)x))
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
index af50eda5d..07f48b955 100644
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ b/src/OSSupport/BlockingTCPLink.cpp
@@ -70,7 +70,7 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
}
}
- server.sin_addr.s_addr = *((unsigned long *)hp->h_addr);
+ memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
server.sin_family = AF_INET;
server.sin_port = htons( (unsigned short)iPort);
if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
@@ -89,6 +89,8 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
{
+ UNUSED(a_Flags);
+
ASSERT(m_Socket.IsValid());
if (!m_Socket.IsValid())
{
@@ -104,6 +106,8 @@ int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* =
int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
{
+ UNUSED(a_Flags);
+
ASSERT(m_Socket.IsValid());
if (!m_Socket.IsValid())
{
diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp
index 2e05f1df1..6072b6ac6 100644
--- a/src/OSSupport/Errors.cpp
+++ b/src/OSSupport/Errors.cpp
@@ -22,7 +22,7 @@ AString GetOSErrorString( int a_ErrNo )
// According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
- #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
+ #if !defined(__APPLE__) && ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
if( res != NULL )
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 17070030f..7f0f0ad2f 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -152,7 +152,7 @@ int cFile::Read (void * iBuffer, int iNumBytes)
return -1;
}
- return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
+ return (int)fread(iBuffer, 1, (size_t)iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count
}
@@ -168,7 +168,7 @@ int cFile::Write(const void * iBuffer, int iNumBytes)
return -1;
}
- int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
+ int res = (int)fwrite(iBuffer, 1, (size_t)iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
return res;
}
@@ -189,7 +189,7 @@ int cFile::Seek (int iPosition)
{
return -1;
}
- return ftell(m_File);
+ return (int)ftell(m_File);
}
@@ -206,7 +206,7 @@ int cFile::Tell (void) const
return -1;
}
- return ftell(m_File);
+ return (int)ftell(m_File);
}
@@ -222,7 +222,7 @@ int cFile::GetSize(void) const
return -1;
}
- int CurPos = ftell(m_File);
+ int CurPos = Tell();
if (CurPos < 0)
{
return -1;
@@ -231,8 +231,8 @@ int cFile::GetSize(void) const
{
return -1;
}
- int res = ftell(m_File);
- if (fseek(m_File, CurPos, SEEK_SET) != 0)
+ int res = Tell();
+ if (fseek(m_File, (long)CurPos, SEEK_SET) != 0)
{
return -1;
}
@@ -255,7 +255,7 @@ int cFile::ReadRestOfFile(AString & a_Contents)
int DataSize = GetSize() - Tell();
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
- a_Contents.assign(DataSize, '\0');
+ a_Contents.assign((size_t)DataSize, '\0');
return Read((void *)a_Contents.data(), DataSize);
}
@@ -350,7 +350,7 @@ int cFile::GetSize(const AString & a_FileName)
struct stat st;
if (stat(a_FileName.c_str(), &st) == 0)
{
- return st.st_size;
+ return (int)st.st_size;
}
return -1;
}
@@ -456,7 +456,7 @@ int cFile::Printf(const char * a_Fmt, ...)
va_start(args, a_Fmt);
AppendVPrintf(buf, a_Fmt, args);
va_end(args);
- return Write(buf.c_str(), buf.length());
+ return Write(buf.c_str(), (int)buf.length());
}
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index 07fce6661..b394c5cb9 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -131,7 +131,7 @@ public:
/** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */
static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp
- int Printf(const char * a_Fmt, ...);
+ int Printf(const char * a_Fmt, ...) FORMATSTRING(2, 3);
/** Flushes all the bufferef output into the file (only when writing) */
void Flush(void);
diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp
index cbf6be6c4..7a8433f4f 100644
--- a/src/OSSupport/GZipFile.cpp
+++ b/src/OSSupport/GZipFile.cpp
@@ -73,12 +73,15 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents)
// Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck!
int NumBytesRead = 0;
+ int TotalBytes = 0;
char Buffer[64 KiB];
while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0)
{
- a_Contents.append(Buffer, NumBytesRead);
+ TotalBytes += NumBytesRead;
+ a_Contents.append(Buffer, (size_t)NumBytesRead);
}
- return NumBytesRead;
+ // NumBytesRead is < 0 on error
+ return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead;
}
@@ -99,7 +102,7 @@ bool cGZipFile::Write(const char * a_Contents, int a_Size)
return false;
}
- return (gzwrite(m_File, a_Contents, a_Size) != 0);
+ return (gzwrite(m_File, a_Contents, (unsigned int)a_Size) != 0);
}
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index b8784ea33..42b8bfdda 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -34,7 +34,7 @@ protected:
public:
cIsThread(const AString & iThreadName);
- ~cIsThread();
+ virtual ~cIsThread();
/// Starts the thread; returns without waiting for the actual start
bool Start(void);
diff --git a/src/OSSupport/ListenThread.h b/src/OSSupport/ListenThread.h
index 4e337d814..b2d806c82 100644
--- a/src/OSSupport/ListenThread.h
+++ b/src/OSSupport/ListenThread.h
@@ -29,43 +29,45 @@ class cListenThread :
typedef cIsThread super;
public:
- /// Used as the callback for connection events
+ /** Used as the callback for connection events */
class cCallback
{
public:
- /// This callback is called whenever a socket connection is accepted
+ virtual ~cCallback() {}
+
+ /** This callback is called whenever a socket connection is accepted */
virtual void OnConnectionAccepted(cSocket & a_Socket) = 0;
} ;
cListenThread(cCallback & a_Callback, cSocket::eFamily a_Family, const AString & a_ServiceName = "");
~cListenThread();
- /// Creates all the sockets, returns trus if successful, false if not.
+ /** Creates all the sockets, returns trus if successful, false if not. */
bool Initialize(const AString & a_PortsString);
bool Start(void);
void Stop(void);
- /// Call before Initialize() to set the "reuse" flag on the sockets
+ /** Call before Initialize() to set the "reuse" flag on the sockets */
void SetReuseAddr(bool a_Reuse = true);
protected:
typedef std::vector<cSocket> cSockets;
- /// The callback which to notify of incoming connections
+ /** The callback which to notify of incoming connections */
cCallback & m_Callback;
- /// Socket address family to use
+ /** Socket address family to use */
cSocket::eFamily m_Family;
- /// Sockets that are being monitored
+ /** Sockets that are being monitored */
cSockets m_Sockets;
- /// If set to true, the SO_REUSEADDR socket option is set to true
+ /** If set to true, the SO_REUSEADDR socket option is set to true */
bool m_ShouldReuseAddr;
- /// Name of the service that's listening on the ports; for logging purposes only
+ /** Name of the service that's listening on the ports; for logging purposes only */
AString m_ServiceName;
diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h
index 5298c15da..0ec0adf9d 100644
--- a/src/OSSupport/Sleep.h
+++ b/src/OSSupport/Sleep.h
@@ -4,4 +4,4 @@ class cSleep
{
public:
static void MilliSleep( unsigned int a_MilliSeconds );
-}; \ No newline at end of file
+};
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index 6afaceedf..c29e495c3 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -307,7 +307,8 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
CloseSocket();
return false;
}
- addr = *((unsigned long*)hp->h_addr);
+ // Should be optimised to a single word copy
+ memcpy(&addr, hp->h_addr, hp->h_length);
}
sockaddr_in server;
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index a02661d2c..0bc1d6b55 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -54,7 +54,7 @@ bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client)
}
// No thread has free space, create a new one:
- LOGD("Creating a new cSocketThread (currently have %d)", m_Threads.size());
+ LOGD("Creating a new cSocketThread (currently have " SIZE_T_FMT ")", m_Threads.size());
cSocketThread * Thread = new cSocketThread(this);
if (!Thread->Start())
{
diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h
index fcd2ce11f..b2eb5950f 100644
--- a/src/OSSupport/SocketThreads.h
+++ b/src/OSSupport/SocketThreads.h
@@ -103,7 +103,7 @@ private:
public:
cSocketThread(cSocketThreads * a_Parent);
- ~cSocketThread();
+ virtual ~cSocketThread();
// All these methods assume parent's m_CS is locked
bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; }
diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h
index 3c9316424..4153b2427 100644
--- a/src/OSSupport/Thread.h
+++ b/src/OSSupport/Thread.h
@@ -23,4 +23,4 @@ private:
cEvent* m_StopEvent;
AString m_ThreadName;
-}; \ No newline at end of file
+};
diff --git a/src/Piston.cpp b/src/Piston.cpp
index 5eb14451d..b21d576f3 100644
--- a/src/Piston.cpp
+++ b/src/Piston.cpp
@@ -242,7 +242,7 @@ bool cPiston::CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
bool cPiston::CanBreakPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
UNUSED(a_BlockMeta);
- return g_BlockPistonBreakable[a_BlockType];
+ return cBlockInfo::IsPistonBreakable(a_BlockType);
}
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index b5560f7c1..d3383bf0d 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -52,7 +52,7 @@ public:
virtual ~cProtocol() {}
/// Called when client sends some data
- virtual void DataReceived(const char * a_Data, int a_Size) = 0;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 3980350f5..fe6280218 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -239,32 +239,11 @@ void cProtocol125::SendChat(const AString & a_Message)
void cProtocol125::SendChat(const cCompositeChat & a_Message)
{
// This version doesn't support composite messages, just extract each part's text and use it:
- AString Msg;
- const cCompositeChat::cParts & Parts = a_Message.GetParts();
- for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr)
- {
- switch ((*itr)->m_PartType)
- {
- case cCompositeChat::ptText:
- case cCompositeChat::ptClientTranslated:
- case cCompositeChat::ptRunCommand:
- case cCompositeChat::ptSuggestCommand:
- {
- Msg.append((*itr)->m_Text);
- break;
- }
- case cCompositeChat::ptUrl:
- {
- Msg.append(((cCompositeChat::cUrlPart *)(*itr))->m_Url);
- break;
- }
- } // switch (PartType)
- } // for itr - Parts[]
// Send the message:
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_CHAT);
- WriteString(Msg);
+ WriteString(a_Message.ExtractText());
Flush();
}
@@ -1186,7 +1165,7 @@ void cProtocol125::SendData(const char * a_Data, int a_Size)
-void cProtocol125::DataReceived(const char * a_Data, int a_Size)
+void cProtocol125::DataReceived(const char * a_Data, size_t a_Size)
{
if (!m_ReceivedData.Write(a_Data, a_Size))
{
@@ -1269,19 +1248,6 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
-#define HANDLE_PACKET_PARSE(Packet) \
- { \
- int res = Packet.Parse(m_ReceivedData); \
- if (res < 0) \
- { \
- return res; \
- } \
- }
-
-
-
-
-
int cProtocol125::ParseArmAnim(void)
{
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
@@ -1375,7 +1341,16 @@ int cProtocol125::ParseEntityAction(void)
{
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
@@ -1976,6 +1951,14 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything
break;
}
+ case cMonster::mtWither:
+ {
+ WriteByte(0x54); // Int at index 20
+ WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
case cMonster::mtMagmaCube:
{
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 1d1484a60..aca24c03a 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -11,6 +11,7 @@
#include "Protocol.h"
#include "../ByteBuffer.h"
+#include "../Entities/Painting.h"
@@ -24,7 +25,7 @@ public:
cProtocol125(cClientHandle * a_Client);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
@@ -57,9 +58,17 @@ public:
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
- virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override {} // This protocol doesn't support such message
+ virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override
+ {
+ // This protocol doesn't support such message
+ UNUSED(a_ID);
+ UNUSED(a_Scale);
+ }
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
- virtual void SendPaintingSpawn (const cPainting & a_Painting) override {};
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) override
+ {
+ UNUSED(a_Painting);
+ };
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
@@ -73,7 +82,12 @@ public:
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
- virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override {} // This protocol doesn't support such message
+ virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override
+ {
+ UNUSED(a_Name);
+ UNUSED(a_DisplayName);
+ UNUSED(a_Mode);
+ } // This protocol doesn't support such message
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 1f9222a69..be9c503ed 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -100,7 +100,7 @@ cProtocol132::~cProtocol132()
{
if (!m_DataToSend.empty())
{
- LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size());
+ LOGD("There are " SIZE_T_FMT " unsent bytes while deleting cProtocol132", m_DataToSend.size());
}
}
@@ -108,7 +108,7 @@ cProtocol132::~cProtocol132()
-void cProtocol132::DataReceived(const char * a_Data, int a_Size)
+void cProtocol132::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 89f4636f5..0702fbf5a 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -40,7 +40,7 @@ public:
virtual ~cProtocol132();
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
// Sending commands (alphabetically sorted):
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp
index cfa27b3c4..ecb24254f 100644
--- a/src/Protocol/Protocol16x.cpp
+++ b/src/Protocol/Protocol16x.cpp
@@ -135,7 +135,7 @@ void cProtocol161::SendPlayerMaxSpeed(void)
WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
- WriteDouble(m_Client->GetPlayer()->GetMaxSpeed());
+ WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
Flush();
}
@@ -184,7 +184,16 @@ int cProtocol161::ParseEntityAction(void)
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
@@ -258,7 +267,7 @@ void cProtocol162::SendPlayerMaxSpeed(void)
WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(1);
WriteString("generic.movementSpeed");
- WriteDouble(m_Client->GetPlayer()->GetMaxSpeed());
+ WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
WriteShort(0);
Flush();
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 992023464..c678fc9a0 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -29,6 +29,7 @@ Implements the 1.7.x protocol classes:
#include "../UI/Window.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../CompositeChat.h"
@@ -97,7 +98,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
-void cProtocol172::DataReceived(const char * a_Data, int a_Size)
+void cProtocol172::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
@@ -686,9 +687,8 @@ void cProtocol172::SendPlayerAbilities(void)
Flags |= 0x04;
}
Pkt.WriteByte(Flags);
- // TODO: Pkt.WriteFloat(m_Client->GetPlayer()->GetMaxFlyingSpeed());
- Pkt.WriteFloat(0.05f);
- Pkt.WriteFloat((float)m_Client->GetPlayer()->GetMaxSpeed());
+ Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed()));
+ Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed()));
}
@@ -742,13 +742,14 @@ void cProtocol172::SendPlayerMaxSpeed(void)
Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID());
Pkt.WriteInt(1); // Count
Pkt.WriteString("generic.movementSpeed");
- Pkt.WriteDouble(0.1);
+ // The default game speed is 0.1, multiply that value by the relative speed:
+ Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed());
if (m_Client->GetPlayer()->IsSprinting())
{
Pkt.WriteShort(1); // Modifier count
Pkt.WriteInt64(0x662a6b8dda3e4c1c);
Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier
- Pkt.WriteDouble(0.3);
+ Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed());
Pkt.WriteByte(2);
}
else
@@ -1115,6 +1116,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
+ case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
}
Pkt.WriteByte(Action);
@@ -1242,14 +1244,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (m_ReceivedData.GetReadableSpace() > 0)
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
- m_CommLogFile.Printf("Incoming data, %d (0x%x) unparsed bytes already present in buffer:\n%s\n",
+ m_CommLogFile.Printf("Incoming data, " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") unparsed bytes already present in buffer:\n%s\n",
AllData.size(), AllData.size(), Hex.c_str()
);
}
@@ -1342,14 +1344,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
- LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
+ LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read " SIZE_T_FMT " bytes, packet contained %u bytes",
PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
);
// Put a message in the comm log:
if (g_ShouldLogCommIn)
{
- m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
+ m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got " SIZE_T_FMT " left) ^^^^^^\n\n\n",
1, bb.GetReadableSpace()
);
m_CommLogFile.Flush();
@@ -1364,14 +1366,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0))
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
- m_CommLogFile.Printf("There are %d (0x%x) bytes of non-parse-able data left in the buffer:\n%s",
+ m_CommLogFile.Printf("There are " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") bytes of non-parse-able data left in the buffer:\n%s",
m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str()
);
m_CommLogFile.Flush();
@@ -1730,7 +1732,15 @@ 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);
- m_Client->HandleEntityAction(PlayerID, Action);
+
+ switch (Action)
+ {
+ case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
+ }
}
@@ -2052,7 +2062,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
AString HexDump;
CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16);
- LOGWARNING("Cannot unGZIP item metadata (%u bytes):\n%s", a_Metadata.size(), HexDump.c_str());
+ LOGWARNING("Cannot unGZIP item metadata (" SIZE_T_FMT " bytes):\n%s", a_Metadata.size(), HexDump.c_str());
return;
}
@@ -2062,43 +2072,54 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
AString HexDump;
CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16);
- LOGWARNING("Cannot parse NBT item metadata: (%u bytes)\n%s", Uncompressed.size(), HexDump.c_str());
+ LOGWARNING("Cannot parse NBT item metadata: (" SIZE_T_FMT " bytes)\n%s", Uncompressed.size(), HexDump.c_str());
return;
}
// Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
- if (
- (NBT.GetType(tag) == TAG_List) &&
- (
- (NBT.GetName(tag) == "ench") ||
- (NBT.GetName(tag) == "StoredEnchantments")
- )
- )
- {
- EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
- }
- else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
+ AString TagName = NBT.GetName(tag);
+ switch (NBT.GetType(tag))
{
- for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
+ case TAG_List:
{
- if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
{
- a_Item.m_CustomName = NBT.GetString(displaytag);
+ EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
}
- else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ break;
+ }
+ case TAG_Compound:
+ {
+ if (TagName == "display") // Custom name and lore tag
{
- AString Lore;
-
- for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
{
- AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ {
+ a_Item.m_CustomName = NBT.GetString(displaytag);
+ }
+ else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ {
+ AString Lore;
+
+ for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ {
+ AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ }
+
+ a_Item.m_Lore = Lore;
+ }
}
-
- a_Item.m_Lore = Lore;
}
+ else if ((TagName == "Fireworks") || (TagName == "Explosion"))
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+ break;
}
+ default: LOGD("Unimplemented NBT data when parsing!"); break;
}
}
}
@@ -2262,7 +2283,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
+ 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);
return;
@@ -2301,6 +2322,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
}
Writer.EndCompound();
}
+ 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);
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -2345,7 +2370,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
case E_BLOCK_HEAD:
{
cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity;
-
+
Writer.AddInt("x", MobHeadEntity.GetPosX());
Writer.AddInt("y", MobHeadEntity.GetPosY());
Writer.AddInt("z", MobHeadEntity.GetPosZ());
@@ -2355,6 +2380,18 @@ 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;
+
+ Writer.AddInt("x", FlowerPotEntity.GetPosX());
+ Writer.AddInt("y", FlowerPotEntity.GetPosY());
+ Writer.AddInt("z", FlowerPotEntity.GetPosZ());
+ Writer.AddInt("Item", (Int32) FlowerPotEntity.GetItem().m_ItemType);
+ Writer.AddInt("Data", (Int32) FlowerPotEntity.GetItem().m_ItemDamage);
+ Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
+ break;
+ }
default: break;
}
@@ -2465,10 +2502,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
}
case cEntity::etProjectile:
{
- if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)
+ cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
+ switch (Projectile.GetProjectileKind())
{
- WriteByte(0x10);
- WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ case cProjectileEntity::pkArrow:
+ {
+ WriteByte(0x10);
+ WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ break;
+ }
+ case cProjectileEntity::pkFirework:
+ {
+ WriteByte(0xA8);
+ WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
+ break;
+ }
+ default: break;
}
break;
}
@@ -2486,6 +2535,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteByte(Frame.GetRotation());
break;
}
+ default: break;
}
}
@@ -2610,6 +2660,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0);
break;
}
+
+ case cMonster::mtWither:
+ {
+ WriteByte(0x54); // Int at index 20
+ WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteByte(0x66); // Float at index 6
+ WriteFloat((float)(a_Mob.GetHealth()));
+ break;
+ }
case cMonster::mtSlime:
{
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 113501568..41163009e 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -56,7 +56,7 @@ public:
cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
/** Called when client sends some data: */
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 84b052146..3b9003e60 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -68,7 +68,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
-void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size)
+void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_Protocol == NULL)
{
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 6aaafedeb..d7fb8fad2 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -59,7 +59,7 @@ public:
static AString GetVersionTextFromInt(int a_ProtocolVersion);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/RCONServer.h b/src/RCONServer.h
index 0e89800a2..88aac4b5f 100644
--- a/src/RCONServer.h
+++ b/src/RCONServer.h
@@ -29,7 +29,7 @@ class cRCONServer :
{
public:
cRCONServer(cServer & a_Server);
- ~cRCONServer();
+ virtual ~cRCONServer();
void Initialize(cIniFile & a_IniFile);
diff --git a/src/Root.cpp b/src/Root.cpp
index af2cb9e4b..ba4398b35 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -245,7 +245,6 @@ void cRoot::Start(void)
delete m_PluginManager; m_PluginManager = NULL;
cItemHandler::Deinit();
- cBlockHandler::Deinit();
LOG("Cleaning up...");
delete m_Server; m_Server = NULL;
@@ -305,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile)
{
if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld")
{
+ IniFile.DeleteKeyComment("Worlds", 0);
IniFile.AddKeyComment("Worlds", " World=secondworld");
}
}
@@ -594,7 +594,6 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
unsigned m_NameLength;
const AString m_PlayerName;
- cPlayerListCallback & m_Callback;
virtual bool Item (cPlayer * a_pPlayer)
{
unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
@@ -616,18 +615,17 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
}
public:
- cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) :
+ cCallback (const AString & a_PlayerName) :
m_BestRating(0),
m_NameLength(a_PlayerName.length()),
m_PlayerName(a_PlayerName),
- m_Callback(a_Callback),
m_BestMatch(NULL),
m_NumMatches(0)
{}
cPlayer * m_BestMatch;
unsigned m_NumMatches;
- } Callback (a_PlayerName, a_Callback);
+ } Callback (a_PlayerName);
ForEachPlayer( Callback );
if (Callback.m_NumMatches == 1)
@@ -781,11 +779,11 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output)
int Mem = NumValid * sizeof(cChunk);
a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (Mem + 1023) / 1024, (Mem + 1024 * 1024 - 1) / (1024 * 1024));
a_Output.Out(" Per-chunk memory size breakdown:");
- a_Output.Out(" block types: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
- a_Output.Out(" block metadata: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- a_Output.Out(" block lighting: %6d bytes (%3d KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- a_Output.Out(" heightmap: %6d bytes (%3d KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
- a_Output.Out(" biomemap: %6d bytes (%3d KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
+ a_Output.Out(" block types: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
+ a_Output.Out(" block metadata: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" block lighting: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" heightmap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
+ a_Output.Out(" biomemap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap);
a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024);
SumNumValid += NumValid;
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
index 61ecac5b7..4c89ce265 100644
--- a/src/Scoreboard.cpp
+++ b/src/Scoreboard.cpp
@@ -17,22 +17,26 @@ AString cObjective::TypeToString(eType a_Type)
{
switch (a_Type)
{
- case E_TYPE_DUMMY: return "dummy";
- case E_TYPE_DEATH_COUNT: return "deathCount";
- case E_TYPE_PLAYER_KILL_COUNT: return "playerKillCount";
- case E_TYPE_TOTAL_KILL_COUNT: return "totalKillCount";
- case E_TYPE_HEALTH: return "health";
- case E_TYPE_ACHIEVEMENT: return "achievement";
- case E_TYPE_STAT: return "stat";
- case E_TYPE_STAT_ITEM_CRAFT: return "stat.craftItem";
- case E_TYPE_STAT_ITEM_USE: return "stat.useItem";
- case E_TYPE_STAT_ITEM_BREAK: return "stat.breakItem";
- case E_TYPE_STAT_BLOCK_MINE: return "stat.mineBlock";
- case E_TYPE_STAT_ENTITY_KILL: return "stat.killEntity";
- case E_TYPE_STAT_ENTITY_KILLED_BY: return "stat.entityKilledBy";
-
+ case otDummy: return "dummy";
+ case otDeathCount: return "deathCount";
+ case otPlayerKillCount: return "playerKillCount";
+ case otTotalKillCount: return "totalKillCount";
+ case otHealth: return "health";
+ case otAchievement: return "achievement";
+ case otStat: return "stat";
+ case otStatItemCraft: return "stat.craftItem";
+ case otStatItemUse: return "stat.useItem";
+ case otStatItemBreak: return "stat.breakItem";
+ case otStatBlockMine: return "stat.mineBlock";
+ case otStatEntityKill: return "stat.killEntity";
+ case otStatEntityKilledBy: return "stat.entityKilledBy";
+
+ // clang optimisises this line away then warns that it has done so.
+ #if !defined(__clang__)
default: return "";
+ #endif
}
+
}
@@ -46,19 +50,19 @@ cObjective::eType cObjective::StringToType(const AString & a_Name)
const char * m_String;
} TypeMap [] =
{
- {E_TYPE_DUMMY, "dummy"},
- {E_TYPE_DEATH_COUNT, "deathCount"},
- {E_TYPE_PLAYER_KILL_COUNT, "playerKillCount"},
- {E_TYPE_TOTAL_KILL_COUNT, "totalKillCount"},
- {E_TYPE_HEALTH, "health"},
- {E_TYPE_ACHIEVEMENT, "achievement"},
- {E_TYPE_STAT, "stat"},
- {E_TYPE_STAT_ITEM_CRAFT, "stat.craftItem"},
- {E_TYPE_STAT_ITEM_USE, "stat.useItem"},
- {E_TYPE_STAT_ITEM_BREAK, "stat.breakItem"},
- {E_TYPE_STAT_BLOCK_MINE, "stat.mineBlock"},
- {E_TYPE_STAT_ENTITY_KILL, "stat.killEntity"},
- {E_TYPE_STAT_ENTITY_KILLED_BY, "stat.entityKilledBy"}
+ {otDummy, "dummy" },
+ {otDeathCount, "deathCount" },
+ {otPlayerKillCount, "playerKillCount" },
+ {otTotalKillCount, "totalKillCount" },
+ {otHealth, "health" },
+ {otAchievement, "achievement" },
+ {otStat, "stat" },
+ {otStatItemCraft, "stat.craftItem" },
+ {otStatItemUse, "stat.useItem" },
+ {otStatItemBreak, "stat.breakItem" },
+ {otStatBlockMine, "stat.mineBlock" },
+ {otStatEntityKill, "stat.killEntity" },
+ {otStatEntityKilledBy, "stat.entityKilledBy"}
};
for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++)
{
@@ -67,7 +71,7 @@ cObjective::eType cObjective::StringToType(const AString & a_Name)
return TypeMap[i].m_Type;
}
} // for i - TypeMap[]
- return E_TYPE_DUMMY;
+ return otDummy;
}
@@ -246,6 +250,17 @@ void cTeam::Reset(void)
+void cTeam::SetDisplayName(const AString & a_Name)
+{
+ m_DisplayName = a_Name;
+
+ // TODO 2014-03-01 xdot: Update clients
+}
+
+
+
+
+
unsigned int cTeam::GetNumPlayers(void) const
{
return m_Players.size();
@@ -257,7 +272,7 @@ unsigned int cTeam::GetNumPlayers(void) const
cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
{
- for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
+ for (int i = 0; i < (int) dsCount; ++i)
{
m_Display[i] = NULL;
}
@@ -301,11 +316,19 @@ bool cScoreboard::RemoveObjective(const AString & a_Name)
return false;
}
- m_Objectives.erase(it);
-
ASSERT(m_World != NULL);
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
+ for (unsigned int i = 0; i < (unsigned int) dsCount; ++i)
+ {
+ if (m_Display[i] == &it->second)
+ {
+ SetDisplay(NULL, (eDisplaySlot) i);
+ }
+ }
+
+ m_Objectives.erase(it);
+
return true;
}
@@ -410,7 +433,7 @@ cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name)
void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
{
- ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
+ ASSERT(a_Slot < dsCount);
cObjective * Objective = GetObjective(a_Objective);
@@ -435,7 +458,7 @@ void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot)
cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
{
- ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
+ ASSERT(a_Slot < dsCount);
return m_Display[a_Slot];
}
@@ -444,7 +467,7 @@ cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
-void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback)
+bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback)
{
cCSLock Lock(m_CSObjectives);
@@ -455,10 +478,66 @@ void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallb
// Call callback
if (a_Callback.Item(&it->second))
{
- return;
+ return false;
}
}
}
+ return true;
+}
+
+
+
+
+
+bool cScoreboard::ForEachObjective(cObjectiveCallback& a_Callback)
+{
+ cCSLock Lock(m_CSObjectives);
+
+ for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
+ {
+ // Call callback
+ if (a_Callback.Item(&it->second))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
+{
+ cCSLock Lock(m_CSTeams);
+
+ for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
+ {
+ // Call callback
+ if (a_Callback.Item(&it->second))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+void cScoreboard::AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value)
+{
+ cCSLock Lock(m_CSObjectives);
+
+ for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
+ {
+ if (it->second.GetType() == a_Type)
+ {
+ it->second.AddScore(a_Name, a_Value);
+ }
+ }
}
@@ -474,7 +553,7 @@ void cScoreboard::SendTo(cClientHandle & a_Client)
it->second.SendTo(a_Client);
}
- for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
+ for (int i = 0; i < (int) dsCount; ++i)
{
// Avoid race conditions
cObjective * Objective = m_Display[i];
diff --git a/src/Scoreboard.h b/src/Scoreboard.h
index f64ba2bce..2fae5e499 100644
--- a/src/Scoreboard.h
+++ b/src/Scoreboard.h
@@ -14,9 +14,11 @@
class cObjective;
+class cTeam;
class cWorld;
typedef cItemCallback<cObjective> cObjectiveCallback;
+typedef cItemCallback<cTeam> cTeamCallback;
@@ -31,23 +33,23 @@ public:
enum eType
{
- E_TYPE_DUMMY,
+ otDummy,
- E_TYPE_DEATH_COUNT,
- E_TYPE_PLAYER_KILL_COUNT,
- E_TYPE_TOTAL_KILL_COUNT,
- E_TYPE_HEALTH,
+ otDeathCount,
+ otPlayerKillCount,
+ otTotalKillCount,
+ otHealth,
- E_TYPE_ACHIEVEMENT,
+ otAchievement,
- E_TYPE_STAT,
- E_TYPE_STAT_ITEM_CRAFT,
- E_TYPE_STAT_ITEM_USE,
- E_TYPE_STAT_ITEM_BREAK,
+ otStat,
+ otStatItemCraft,
+ otStatItemUse,
+ otStatItemBreak,
- E_TYPE_STAT_BLOCK_MINE,
- E_TYPE_STAT_ENTITY_KILL,
- E_TYPE_STAT_ENTITY_KILLED_BY
+ otStatBlockMine,
+ otStatEntityKill,
+ otStatEntityKilledBy
};
// tolua_end
@@ -67,31 +69,37 @@ public:
const AString & GetName(void) const { return m_Name; }
const AString & GetDisplayName(void) const { return m_DisplayName; }
- /// Resets the objective
+ /** Resets the objective */
void Reset(void);
- /// Returns the score of the specified player
+ /** Returns the score of the specified player */
Score GetScore(const AString & a_Name) const;
- /// Sets the score of the specified player
+ /** Sets the score of the specified player */
void SetScore(const AString & a_Name, Score a_Score);
- /// Resets the score of the specified player
+ /** Resets the score of the specified player */
void ResetScore(const AString & a_Name);
- /// Adds a_Delta and returns the new score
+ /** Adds a_Delta and returns the new score */
Score AddScore(const AString & a_Name, Score a_Delta);
- /// Subtracts a_Delta and returns the new score
+ /** Subtracts a_Delta and returns the new score */
Score SubScore(const AString & a_Name, Score a_Delta);
void SetDisplayName(const AString & a_Name);
// tolua_end
- /// Send this objective to the specified client
+ /** Send this objective to the specified client */
void SendTo(cClientHandle & a_Client);
+ static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
+ {
+ return "cObjective";
+ }
+
+
private:
typedef std::pair<AString, Score> cTrackedPlayer;
@@ -109,7 +117,8 @@ private:
friend class cScoreboardSerializer;
-};
+
+}; // tolua_export
@@ -127,21 +136,23 @@ public:
const AString & a_Prefix, const AString & a_Suffix
);
- /// Adds a new player to the team
+ // tolua_begin
+
+ /** Adds a new player to the team */
bool AddPlayer(const AString & a_Name);
- /// Removes a player from the team
+ /** Removes a player from the team */
bool RemovePlayer(const AString & a_Name);
- /// Returns whether the specified player is in this team
+ /** Returns whether the specified player is in this team */
bool HasPlayer(const AString & a_Name) const;
- /// Removes all registered players
+ /** Removes all registered players */
void Reset(void);
// tolua_begin
- /// Returns the number of registered players
+ /** Returns the number of registered players */
unsigned int GetNumPlayers(void) const;
bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; }
@@ -163,6 +174,11 @@ public:
// tolua_end
+ static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
+ {
+ return "cTeam";
+ }
+
private:
typedef std::set<AString> cPlayerNameSet;
@@ -180,7 +196,8 @@ private:
friend class cScoreboardSerializer;
-};
+
+}; // tolua_export
@@ -193,11 +210,11 @@ public:
enum eDisplaySlot
{
- E_DISPLAY_SLOT_LIST = 0,
- E_DISPLAY_SLOT_SIDEBAR,
- E_DISPLAY_SLOT_NAME,
+ dsList = 0,
+ dsSidebar,
+ dsName,
- E_DISPLAY_SLOT_COUNT
+ dsCount
};
// tolua_end
@@ -209,44 +226,61 @@ public:
// tolua_begin
- /// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision
+ /** Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision */
cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type);
- /// Removes a registered objective, returns true if operation was successful
+ /** Removes a registered objective, returns true if operation was successful */
bool RemoveObjective(const AString & a_Name);
- /// Retrieves the objective with the specified name, NULL if not found
+ /** Retrieves the objective with the specified name, NULL if not found */
cObjective * GetObjective(const AString & a_Name);
- /// Registers a new team, returns the cTeam instance, NULL on name collision
+ /** Registers a new team, returns the cTeam instance, NULL on name collision */
cTeam * RegisterTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix);
- /// Removes a registered team, returns true if operation was successful
+ /** Removes a registered team, returns true if operation was successful */
bool RemoveTeam(const AString & a_Name);
- /// Retrieves the team with the specified name, NULL if not found
+ /** Retrieves the team with the specified name, NULL if not found */
cTeam * GetTeam(const AString & a_Name);
- cTeam * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
-
void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot);
- void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot);
-
cObjective * GetObjectiveIn(eDisplaySlot a_Slot);
- /// Execute callback for each objective with the specified type
- void ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback);
-
unsigned int GetNumObjectives(void) const;
unsigned int GetNumTeams(void) const;
+ void AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value = 1);
+
// tolua_end
- /// Send this scoreboard to the specified client
+ /** Send this scoreboard to the specified client */
void SendTo(cClientHandle & a_Client);
+ cTeam * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
+
+ /** Execute callback for each objective with the specified type
+ *
+ * Returns true if all objectives processed, false if the callback aborted by returning true.
+ */
+ bool ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback);
+
+ /** Execute callback for each objective.
+ *
+ * Returns true if all objectives have been processed, false if the callback aborted by returning true.
+ */
+ bool ForEachObjective(cObjectiveCallback& a_Callback); // Exported in ManualBindings.cpp
+
+ /** Execute callback for each team.
+ *
+ * Returns true if all teams have been processed, false if the callback aborted by returning true.
+ */
+ bool ForEachTeam(cTeamCallback& a_Callback); // Exported in ManualBindings.cpp
+
+ void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot);
+
private:
@@ -265,11 +299,12 @@ private:
cWorld * m_World;
- cObjective* m_Display[E_DISPLAY_SLOT_COUNT];
+ cObjective * m_Display[dsCount];
friend class cScoreboardSerializer;
-} ;
+
+}; // tolua_export
diff --git a/src/Server.cpp b/src/Server.cpp
index fcbcaa919..d1e53bfff 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -24,7 +24,7 @@
#include "MersenneTwister.h"
#include "inifile/iniFile.h"
-#include "Vector3f.h"
+#include "Vector3.h"
#include <fstream>
#include <sstream>
@@ -550,7 +550,7 @@ void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback &
for (AStringPairs::const_iterator itr = Callback.m_Commands.begin(), end = Callback.m_Commands.end(); itr != end; ++itr)
{
const AStringPair & cmd = *itr;
- a_Output.Out(Printf("%-*s%s\n", Callback.m_MaxLen, cmd.first.c_str(), cmd.second.c_str()));
+ a_Output.Out(Printf("%-*s%s\n", static_cast<int>(Callback.m_MaxLen), cmd.first.c_str(), cmd.second.c_str()));
} // for itr - Callback.m_Commands[]
a_Output.Finished();
}
diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp
index 3d2170e44..bc5158d95 100644
--- a/src/Simulator/DelayedFluidSimulator.cpp
+++ b/src/Simulator/DelayedFluidSimulator.cpp
@@ -20,7 +20,7 @@
bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_RelZ)
{
ASSERT(a_RelZ >= 0);
- ASSERT(a_RelZ < ARRAYCOUNT(m_Blocks));
+ ASSERT(a_RelZ < static_cast<int>(ARRAYCOUNT(m_Blocks)));
cCoordWithIntVector & Blocks = m_Blocks[a_RelZ];
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 85190c82b..470dfc791 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -6,6 +6,8 @@
#include "../BlockID.h"
#include "../Defines.h"
#include "../Chunk.h"
+#include "Root.h"
+#include "../Bindings/PluginManager.h"
@@ -252,7 +254,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in
{
return m_BurnStepTimeFuel;
}
- IsBlockBelowSolid = g_BlockIsSolid[BlockBelow];
+ IsBlockBelowSolid = cBlockInfo::IsSolid(BlockBelow);
}
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
@@ -315,9 +317,15 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int
*/
if (CanStartFireInBlock(a_Chunk, x, y, z))
{
- FLOG("FS: Starting new fire at {%d, %d, %d}.",
- x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width
- );
+ int a_PosX = x + a_Chunk->GetPosX() * cChunkDef::Width;
+ int a_PosZ = z + a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, a_PosX, y, a_PosZ, ssFireSpread))
+ {
+ return;
+ }
+
+ FLOG("FS: Starting new fire at {%d, %d, %d}.", a_PosX, y, a_PosZ);
a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0);
}
} // for y
@@ -334,21 +342,33 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
for (size_t i = 0; i < ARRAYCOUNT(gNeighborCoords); i++)
{
BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- if (!a_Chunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta))
+ int X = a_RelX + gNeighborCoords[i].x;
+ int Z = a_RelZ + gNeighborCoords[i].z;
+
+ cChunkPtr Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(X, Z);
+ if (Neighbour == NULL)
{
- // Neighbor not accessible, ignore it
continue;
}
+ BlockType = Neighbour->GetBlock(X, a_RelY + gCrossCoords[i].y, Z);
+
if (!IsFuel(BlockType))
{
continue;
}
+
+ if (BlockType == E_BLOCK_TNT)
+ {
+ int AbsX = X + Neighbour->GetPosX() * cChunkDef::Width;
+ int AbsZ = Z + Neighbour->GetPosZ() * cChunkDef::Width;
+
+ m_World.SpawnPrimedTNT(AbsX, a_RelY + gNeighborCoords[i].y, AbsZ, 0);
+ Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, E_BLOCK_AIR, 0);
+ return;
+ }
+
bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance);
- a_Chunk->UnboundedRelSetBlock(
- a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z,
- ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0
- );
+ Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0);
} // for i - Coords[]
}
diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp
index 95182345c..03e94e791 100644
--- a/src/Simulator/FloodyFluidSimulator.cpp
+++ b/src/Simulator/FloodyFluidSimulator.cpp
@@ -54,14 +54,23 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ)
);
- NIBBLETYPE MyMeta = a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ);
- if (!IsAnyFluidBlock(a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ)))
+ BLOCKTYPE MyBlock; NIBBLETYPE MyMeta;
+ a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta);
+
+ if (!IsAnyFluidBlock(MyBlock))
{
// Can happen - if a block is scheduled for simulating and gets replaced in the meantime.
FLOG(" BadBlockType exit");
return;
}
+ // When in contact with water, lava should harden
+ if (HardenBlock(a_Chunk, a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta))
+ {
+ // Block was changed, bail out
+ return;
+ }
+
if (MyMeta != 0)
{
// Source blocks aren't checked for tributaries, others are.
@@ -86,7 +95,12 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
{
// Spread only down, possibly washing away what's there or turning lava to stone / cobble / obsidian:
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY - 1, a_RelZ, 8);
- SpreadFurther = false;
+
+ // Source blocks spread both downwards and sideways
+ if (MyMeta != 0)
+ {
+ SpreadFurther = false;
+ }
}
// If source creation is on, check for it here:
else if (
@@ -105,10 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
if (SpreadFurther && (NewMeta < 8))
{
// Spread to the neighbors:
- SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, NewMeta);
+ Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
}
// Mark as processed:
@@ -119,6 +130,17 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
+void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+{
+ SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
+}
+
+
+
+
bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta)
{
// If we have a section above, check if there's fluid above this block that would feed it:
@@ -296,6 +318,8 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
a_NewMeta
);
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
+
+ HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
}
@@ -348,3 +372,56 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX
+
+bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
+{
+ // Only lava blocks can harden
+ if (!IsBlockLava(a_BlockType))
+ {
+ return false;
+ }
+
+ bool ShouldHarden = false;
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ static const Vector3i Coords[] =
+ {
+ Vector3i( 1, 0, 0),
+ Vector3i(-1, 0, 0),
+ Vector3i( 0, 0, 1),
+ Vector3i( 0, 0, -1),
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
+ {
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta))
+ {
+ continue;
+ }
+ if (IsBlockWater(BlockType))
+ {
+ ShouldHarden = true;
+ }
+ } // for i - Coords[]
+
+ if (ShouldHarden)
+ {
+ if (a_Meta == 0)
+ {
+ // Source lava block
+ a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0);
+ return true;
+ }
+ // Ignore last lava level
+ else if (a_Meta <= 4)
+ {
+ a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h
index c4af2e246..632de3bb2 100644
--- a/src/Simulator/FloodyFluidSimulator.h
+++ b/src/Simulator/FloodyFluidSimulator.h
@@ -38,14 +38,26 @@ protected:
// cDelayedFluidSimulator overrides:
virtual void SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override;
- /// Checks tributaries, if not fed, decreases the block's level and returns true
+ /** Checks tributaries, if not fed, decreases the block's level and returns true. */
bool CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta);
- /// Spreads into the specified block, if the blocktype there allows. a_Area is for checking.
+ /** Spreads into the specified block, if the blocktype there allows. a_Area is for checking. */
void SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
- /// Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so
+ /** Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so. */
bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
+
+ /** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block.
+ *
+ * Returns whether the block was changed or not.
+ */
+ bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta);
+
+ /** Spread water to neighbors.
+ *
+ * May be overridden to provide more sophisticated algorithms.
+ */
+ virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
} ;
diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp
index 61c93ed73..7779573d7 100644
--- a/src/Simulator/FluidSimulator.cpp
+++ b/src/Simulator/FluidSimulator.cpp
@@ -36,6 +36,7 @@ bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType)
case E_BLOCK_COBWEB:
case E_BLOCK_CROPS:
case E_BLOCK_DEAD_BUSH:
+ case E_BLOCK_LILY_PAD:
case E_BLOCK_RAIL:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index 74b30f920..92659fab7 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -566,14 +566,14 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
{
if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
{
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ)]) // If there is something solid above us (wire cut off)...
+ if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)...
{
continue; // We don't receive power from that wire
}
}
else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
{
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)])
+ if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)))
{
continue;
}
@@ -838,8 +838,8 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
{
m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
}
}
@@ -1062,7 +1062,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
{
Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
- float Distance = (EntityPos - BlockPos).Length();
+ double Distance = (EntityPos - BlockPos).Length();
if (Distance <= 0.7)
{
diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h
index e6bc28621..8b7363366 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.h
+++ b/src/Simulator/IncrementalRedstoneSimulator.h
@@ -170,7 +170,7 @@ private:
/* ====== Misc Functions ====== */
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
- inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return g_BlockFullyOccupiesVoxel[Block]; }
+ inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); }
/** Returns if a block is a mechanism (something that accepts power and does something) */
inline static bool IsMechanism(BLOCKTYPE Block)
diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp
index 06fd0f858..0739f0187 100644
--- a/src/Simulator/Simulator.cpp
+++ b/src/Simulator/Simulator.cpp
@@ -3,7 +3,6 @@
#include "Simulator.h"
#include "../World.h"
-#include "../Vector3i.h"
#include "../BlockID.h"
#include "../Defines.h"
#include "../Chunk.h"
diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h
index a25b7f1b6..a2e2a5742 100644
--- a/src/Simulator/Simulator.h
+++ b/src/Simulator/Simulator.h
@@ -1,7 +1,7 @@
#pragma once
-#include "../Vector3i.h"
+#include "../Vector3.h"
#include "inifile/iniFile.h"
diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp
new file mode 100644
index 000000000..78aff9d68
--- /dev/null
+++ b/src/Simulator/VanillaFluidSimulator.cpp
@@ -0,0 +1,150 @@
+
+// VanillaFluidSimulator.cpp
+
+#include "Globals.h"
+
+#include "VanillaFluidSimulator.h"
+#include "../World.h"
+#include "../Chunk.h"
+#include "../BlockArea.h"
+#include "../Blocks/BlockHandler.h"
+#include "../BlockInServerPluginInterface.h"
+
+
+
+
+
+static const int InfiniteCost = 100;
+
+
+
+
+
+cVanillaFluidSimulator::cVanillaFluidSimulator(
+ cWorld & a_World,
+ BLOCKTYPE a_Fluid,
+ BLOCKTYPE a_StationaryFluid,
+ NIBBLETYPE a_Falloff,
+ int a_TickDelay,
+ int a_NumNeighborsForSource
+) : super(a_World, a_Fluid, a_StationaryFluid, a_Falloff, a_TickDelay, a_NumNeighborsForSource)
+{
+}
+
+
+
+
+
+void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+{
+ int Cost[4];
+ Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
+ Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
+ Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
+ Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
+
+ int MinCost = InfiniteCost;
+ for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
+ {
+ if (Cost[i] < MinCost)
+ {
+ MinCost = Cost[i];
+ }
+ }
+
+ if (Cost[0] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
+ }
+ if (Cost[1] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
+ }
+ if (Cost[2] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
+ }
+ if (Cost[3] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
+ }
+}
+
+
+
+
+
+int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration)
+{
+ int Cost = InfiniteCost;
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+
+ // Check if block is passable
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
+ {
+ return Cost;
+ }
+ if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType))
+ {
+ return Cost;
+ }
+
+ // Check if block below is passable
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
+ {
+ return Cost;
+ }
+ if (IsPassableForFluid(BlockType) || IsBlockLiquid(BlockType))
+ {
+ // Path found, exit
+ return a_Iteration;
+ }
+
+ // 5 blocks away, bail out
+ if (a_Iteration > 3)
+ {
+ return Cost;
+ }
+
+ // Recurse
+ if (a_Dir != X_MINUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != X_PLUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != Z_MINUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != Z_PLUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+
+ return Cost;
+}
+
+
+
+
diff --git a/src/Simulator/VanillaFluidSimulator.h b/src/Simulator/VanillaFluidSimulator.h
new file mode 100644
index 000000000..a9ea98b5a
--- /dev/null
+++ b/src/Simulator/VanillaFluidSimulator.h
@@ -0,0 +1,42 @@
+
+// VanillaFluidSimulator.h
+
+
+
+
+
+#pragma once
+
+#include "FloodyFluidSimulator.h"
+
+
+
+
+
+// fwd:
+class cBlockArea;
+
+
+
+
+
+class cVanillaFluidSimulator :
+ public cFloodyFluidSimulator
+{
+ typedef cFloodyFluidSimulator super;
+
+public:
+ cVanillaFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay, int a_NumNeighborsForSource);
+
+protected:
+ // cFloodyFluidSimulator overrides:
+ virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
+
+ /** Recursively calculates the minimum number of blocks needed to descend a level. */
+ int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0);
+
+} ;
+
+
+
+
diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp
index 5b9a3bb0a..2a85649a1 100644
--- a/src/StringCompression.cpp
+++ b/src/StringCompression.cpp
@@ -53,7 +53,7 @@ int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed
-int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed)
+int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
{
// Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
@@ -83,6 +83,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
{
// Some data has been compressed. Consume the buffer and continue compressing
a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
+ strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{
@@ -116,7 +117,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
-extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed)
+extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
{
// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
@@ -139,13 +140,14 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U
for (;;)
{
- res = inflate(&strm, Z_FINISH);
+ res = inflate(&strm, Z_NO_FLUSH);
switch (res)
{
case Z_OK:
{
// Some data has been uncompressed. Consume the buffer and continue uncompressing
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
+ strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{
diff --git a/src/StringCompression.h b/src/StringCompression.h
index 3f4e12d2d..c3a9eca91 100644
--- a/src/StringCompression.h
+++ b/src/StringCompression.h
@@ -16,10 +16,10 @@ extern int CompressString(const char * a_Data, int a_Length, AString & a_Compres
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
/// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
-extern int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed);
+extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed);
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
-extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed);
+extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 3fe75d611..ad622d707 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -288,13 +288,13 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString &
// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8)
+AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8)
{
a_UTF8.clear();
a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size
for (int i = 0; i < a_NumShorts; i++)
{
- int c = ntohs(*(a_RawData + i));
+ int c = GetBEShort(&a_RawData[i * 2]);
if (c < 0x80)
{
a_UTF8.push_back((char)c);
@@ -364,10 +364,7 @@ Notice from the original file:
#define UNI_MAX_BMP 0x0000FFFF
#define UNI_MAX_UTF16 0x0010FFFF
-#define UNI_MAX_UTF32 0x7FFFFFFF
-#define UNI_MAX_LEGAL_UTF32 0x0010FFFF
#define UNI_SUR_HIGH_START 0xD800
-#define UNI_SUR_HIGH_END 0xDBFF
#define UNI_SUR_LOW_START 0xDC00
#define UNI_SUR_LOW_END 0xDFFF
@@ -457,7 +454,6 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
if (!isLegalUTF8(source, extraBytesToRead + 1))
{
return a_UTF16;
- break;
}
// The cases all fall through. See "Note A" below.
diff --git a/src/StringUtils.h b/src/StringUtils.h
index dfbfc2a75..da395e5b5 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -22,16 +22,16 @@ typedef std::list<AString> AStringList;
/** Add the formated string to the existing data in the string */
-extern AString & AppendVPrintf(AString & str, const char * format, va_list args);
+extern AString & AppendVPrintf(AString & str, const char * format, va_list args) FORMATSTRING(2, 0);
/// Output the formatted text into the string
-extern AString & Printf (AString & str, const char * format, ...);
+extern AString & Printf (AString & str, const char * format, ...) FORMATSTRING(2, 3);
/// Output the formatted text into string, return string by value
-extern AString Printf(const char * format, ...);
+extern AString Printf(const char * format, ...) FORMATSTRING(1, 2);
/// Add the formatted string to the existing data in the string
-extern AString & AppendPrintf (AString & str, const char * format, ...);
+extern AString & AppendPrintf (AString & str, const char * format, ...) FORMATSTRING(2, 3);
/// Split the string at any of the listed delimiters, return as a stringvector
extern AStringVector StringSplit(const AString & str, const AString & delim);
@@ -58,7 +58,7 @@ extern unsigned int RateCompareString(const AString & s1, const AString & s2 );
extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export
/// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-extern AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8);
+extern AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8);
/// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16
extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16);
@@ -79,10 +79,10 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
/// Decodes a Base64-encoded string into the raw data
-extern AString Base64Decode(const AString & a_Base64String);
+extern AString Base64Decode(const AString & a_Base64String); // Exported manually due to embedded NULs and extra parameter
/// Encodes a string into Base64
-extern AString Base64Encode(const AString & a_Input);
+extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter
/// Reads two bytes from the specified memory location and interprets them as BigEndian short
extern short GetBEShort(const char * a_Mem);
diff --git a/src/Tracer.cpp b/src/Tracer.cpp
index ef136302f..6da6b2ad7 100644
--- a/src/Tracer.cpp
+++ b/src/Tracer.cpp
@@ -4,10 +4,6 @@
#include "Tracer.h"
#include "World.h"
-#include "Vector3f.h"
-#include "Vector3i.h"
-#include "Vector3d.h"
-
#include "Entities/Entity.h"
#ifndef _WIN32
@@ -226,7 +222,7 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int
BLOCKTYPE BlockID = m_World->GetBlock(pos.x, pos.y, pos.z);
// Block is counted as a collision if we are not doing a line of sight and it is solid,
// or if the block is not air and not water. That way mobs can still see underwater.
- if ((!a_LineOfSight && g_BlockIsSolid[BlockID]) || (a_LineOfSight && (BlockID != E_BLOCK_AIR) && !IsBlockWater(BlockID)))
+ if ((!a_LineOfSight && cBlockInfo::IsSolid(BlockID)) || (a_LineOfSight && (BlockID != E_BLOCK_AIR) && !IsBlockWater(BlockID)))
{
BlockHitPosition = pos;
int Normal = GetHitNormal(a_Start, End, pos );
diff --git a/src/Tracer.h b/src/Tracer.h
index 6c2ab6792..bdb080f0d 100644
--- a/src/Tracer.h
+++ b/src/Tracer.h
@@ -1,8 +1,7 @@
#pragma once
-#include "Vector3i.h"
-#include "Vector3f.h"
+#include "Vector3.h"
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index bfcad3d92..88977e005 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -224,6 +224,24 @@ void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum)
+void cSlotArea::OnPlayerAdded(cPlayer & a_Player)
+{
+ UNUSED(a_Player);
+}
+
+
+
+
+
+void cSlotArea::OnPlayerRemoved(cPlayer & a_Player)
+{
+ UNUSED(a_Player);
+}
+
+
+
+
+
void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
{
for (int i = 0; i < m_NumSlots; i++)
@@ -447,6 +465,18 @@ void cSlotAreaCrafting::OnPlayerRemoved(cPlayer & a_Player)
+
+void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
+{
+ UNUSED(a_ItemStack);
+ UNUSED(a_Player);
+ UNUSED(a_ShouldApply);
+ UNUSED(a_KeepEmptySlots);
+}
+
+
+
+
void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
{
cItem & DraggingItem = a_Player.GetDraggingItem();
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index d31c87e0c..25b367cff 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -48,10 +48,10 @@ public:
virtual void DblClicked(cPlayer & a_Player, int a_SlotNum);
/// Called when a new player opens the same parent window. The window already tracks the player. CS-locked.
- virtual void OnPlayerAdded(cPlayer & a_Player) {} ;
+ virtual void OnPlayerAdded(cPlayer & a_Player);
/// Called when one of the players closes the parent window. The window already doesn't track the player. CS-locked.
- virtual void OnPlayerRemoved(cPlayer & a_Player) {} ;
+ virtual void OnPlayerRemoved(cPlayer & a_Player);
/** Called to store as much of a_ItemStack in the area as possible. a_ItemStack is modified to reflect the change.
The default implementation searches each slot for available space and distributes the stack there.
@@ -226,7 +226,7 @@ public:
virtual void OnPlayerRemoved(cPlayer & a_Player) 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) override;
protected:
/// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 1a8456f70..aae7b99a3 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -637,7 +637,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
{
if ((size_t)(a_Item.m_ItemCount) < a_SlotNums.size())
{
- LOGWARNING("%s: Distributing less items (%d) than slots (%u)", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size());
+ LOGWARNING("%s: Distributing less items (%d) than slots (" SIZE_T_FMT ")", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size());
// This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now
return 0;
}
diff --git a/src/UI/WindowOwner.h b/src/UI/WindowOwner.h
index d41abf66d..e3c73edc4 100644
--- a/src/UI/WindowOwner.h
+++ b/src/UI/WindowOwner.h
@@ -33,6 +33,10 @@ public:
{
}
+ virtual ~cWindowOwner()
+ {
+ }
+
void CloseWindow(void)
{
m_Window = NULL;
diff --git a/src/Vector3.h b/src/Vector3.h
new file mode 100644
index 000000000..a00e14508
--- /dev/null
+++ b/src/Vector3.h
@@ -0,0 +1,293 @@
+
+#pragma once
+
+
+
+#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
+#include <math.h>
+
+
+
+
+
+template <typename T>
+// tolua_begin
+class Vector3
+{
+
+ TOLUA_TEMPLATE_BIND((T, int, float, double))
+
+public:
+
+ T x, y, z;
+
+
+ inline Vector3(void) : x(0), y(0), z(0) {}
+ inline Vector3(T a_x, T a_y, T a_z) : x(a_x), y(a_y), z(a_z) {}
+
+
+ // Hardcoded copy constructors (tolua++ does not support function templates .. yet)
+ Vector3(const Vector3<float> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+ Vector3(const Vector3<double> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+ Vector3(const Vector3<int> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+
+
+ // tolua_end
+ template <typename _T>
+ Vector3(const Vector3<_T> & a_Rhs) : x(a_Rhs.x), y(a_Rhs.y), z(a_Rhs.z) {}
+
+ template <typename _T>
+ Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {}
+ // tolua_begin
+
+
+ inline void Set(T a_x, T a_y, T a_z)
+ {
+ x = a_x;
+ y = a_y;
+ z = a_z;
+ }
+
+ inline void Normalize(void)
+ {
+ double Len = 1.0 / Length();
+
+ x = (T)(x * Len);
+ y = (T)(y * Len);
+ z = (T)(z * Len);
+ }
+
+ inline Vector3<T> NormalizeCopy(void) const
+ {
+ double Len = 1.0 / Length();
+
+ return Vector3<T>(
+ (T)(x * Len),
+ (T)(y * Len),
+ (T)(z * Len)
+ );
+ }
+
+ inline void NormalizeCopy(Vector3<T> & a_Rhs) const
+ {
+ double Len = 1.0 / Length();
+
+ a_Rhs.Set(
+ (T)(x * Len),
+ (T)(y * Len),
+ (T)(z * Len)
+ );
+ }
+
+ inline double Length(void) const
+ {
+ return sqrt((double)(x * x + y * y + z * z));
+ }
+
+ inline double SqrLength(void) const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ inline T Dot(const Vector3<T> & a_Rhs) const
+ {
+ return x * a_Rhs.x + y * a_Rhs.y + z * a_Rhs.z;
+ }
+
+ inline Vector3<T> Cross(const Vector3<T> & a_Rhs) const
+ {
+ return Vector3<T>(
+ y * a_Rhs.z - z * a_Rhs.y,
+ z * a_Rhs.x - x * a_Rhs.z,
+ x * a_Rhs.y - y * a_Rhs.x
+ );
+ }
+
+ inline bool Equals(const Vector3<T> & a_Rhs) const
+ {
+ return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z;
+ }
+
+ inline bool operator < (const Vector3<T> & a_Rhs)
+ {
+ // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ?
+ return (x < a_Rhs.x) || (x == a_Rhs.x && y < a_Rhs.y) || (x == a_Rhs.x && y == a_Rhs.y && z < a_Rhs.z);
+ }
+
+ inline void Move(T a_X, T a_Y, T a_Z)
+ {
+ x += a_X;
+ y += a_Y;
+ z += a_Z;
+ }
+
+ inline void Move(const Vector3<T> & a_Diff)
+ {
+ x += a_Diff.x;
+ y += a_Diff.y;
+ z += a_Diff.z;
+ }
+
+ // tolua_end
+
+ inline void operator += (const Vector3<T> & a_Rhs)
+ {
+ x += a_Rhs.x;
+ y += a_Rhs.y;
+ z += a_Rhs.z;
+ }
+
+ inline void operator -= (const Vector3<T> & a_Rhs)
+ {
+ x -= a_Rhs.x;
+ y -= a_Rhs.y;
+ z -= a_Rhs.z;
+ }
+
+ inline void operator *= (const Vector3<T> & a_Rhs)
+ {
+ x *= a_Rhs.x;
+ y *= a_Rhs.y;
+ z *= a_Rhs.z;
+ }
+
+ inline void operator *= (T a_v)
+ {
+ x *= a_v;
+ y *= a_v;
+ z *= a_v;
+ }
+
+ // tolua_begin
+
+ inline Vector3<T> operator + (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x + a_Rhs.x,
+ y + a_Rhs.y,
+ z + a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator - (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x - a_Rhs.x,
+ y - a_Rhs.y,
+ z - a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator * (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x * a_Rhs.x,
+ y * a_Rhs.y,
+ z * a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator * (T a_v) const
+ {
+ return Vector3<T>(
+ x * a_v,
+ y * a_v,
+ z * a_v
+ );
+ }
+
+ inline Vector3<T> operator / (T a_v) const
+ {
+ return Vector3<T>(
+ x / a_v,
+ y / a_v,
+ z / a_v
+ );
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).z = a_Z
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToXYPlane(const Vector3<T> & a_OtherEnd, T a_Z) const
+ {
+ if (abs(z - a_OtherEnd.z) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_Z - z) / (a_OtherEnd.z - z);
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).y = a_Y
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToXZPlane(const Vector3<T> & a_OtherEnd, T a_Y) const
+ {
+ if (abs(y - a_OtherEnd.y) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_Y - y) / (a_OtherEnd.y - y);
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).x = a_X
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToYZPlane(const Vector3<T> & a_OtherEnd, T a_X) const
+ {
+ if (abs(x - a_OtherEnd.x) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_X - x) / (a_OtherEnd.x - x);
+ }
+
+ /** The max difference between two coords for which the coords are assumed equal. */
+ static const double EPS;
+
+ /** Return value of LineCoeffToPlane() if the line is parallel to the plane. */
+ static const double NO_INTERSECTION;
+
+};
+// tolua_end
+
+
+
+
+
+template <typename T>
+const double Vector3<T>::EPS = 0.000001;
+
+template <typename T>
+const double Vector3<T>::NO_INTERSECTION = 1e70;
+
+
+
+
+
+// tolua_begin
+typedef Vector3<double> Vector3d;
+typedef Vector3<float> Vector3f;
+typedef Vector3<int> Vector3i;
+// tolua_end
+
+
+
+
+
+typedef std::list<Vector3i> cVector3iList;
+typedef std::vector<Vector3i> cVector3iArray;
+
+
+
+
+
+
diff --git a/src/Vector3d.cpp b/src/Vector3d.cpp
deleted file mode 100644
index 96ebebab5..000000000
--- a/src/Vector3d.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3d.h"
-#include "Vector3f.h"
-
-
-
-
-
-const double Vector3d::EPS = 0.000001; ///< The max difference between two coords for which the coords are assumed equal
-const double Vector3d::NO_INTERSECTION = 1e70; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
-
-
-
-
-
-Vector3d::Vector3d(const Vector3f & v) :
- x(v.x),
- y(v.y),
- z(v.z)
-{
-}
-
-
-
-
-
-Vector3d::Vector3d(const Vector3f * v) :
- x(v->x),
- y(v->y),
- z(v->z)
-{
-}
-
-
-
-
-
-double Vector3d::LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const
-{
- if (abs(z - a_OtherEnd.z) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_Z - z) / (a_OtherEnd.z - z);
-}
-
-
-
-
-
-double Vector3d::LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const
-{
- if (abs(y - a_OtherEnd.y) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_Y - y) / (a_OtherEnd.y - y);
-}
-
-
-
-
-
-double Vector3d::LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const
-{
- if (abs(x - a_OtherEnd.x) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_X - x) / (a_OtherEnd.x - x);
-}
-
-
-
-
diff --git a/src/Vector3d.h b/src/Vector3d.h
deleted file mode 100644
index a06a17c09..000000000
--- a/src/Vector3d.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3f;
-
-
-
-// tolua_begin
-
-class Vector3d
-{
-public:
- // convert from float
- Vector3d(const Vector3f & v);
- Vector3d(const Vector3f * v);
-
- Vector3d() : x(0), y(0), z(0) {}
- Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {}
-
- inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; }
- inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; }
- inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); }
- inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); }
- inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); }
- inline double SqrLength() const { return x * x + y * y + z * z; }
- inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; }
- inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); }
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).z = a_Z
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const;
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).y = a_Y
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const;
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).x = a_X
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const;
-
- inline bool Equals(const Vector3d & v) const { return ((x == v.x) && (y == v.y) && (z == v.z)); }
-
- // tolua_end
-
- void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3d& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
-
- // tolua_begin
-
- Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); }
- Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); }
- Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); }
- Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); }
- Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); }
- Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); }
- Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); }
-
- double x, y, z;
-
- static const double EPS; ///< The max difference between two coords for which the coords are assumed equal
- static const double NO_INTERSECTION; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
-} ;
-
-// tolua_end
-
-
-
-
diff --git a/src/Vector3f.cpp b/src/Vector3f.cpp
deleted file mode 100644
index 59d71d371..000000000
--- a/src/Vector3f.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3f.h"
-#include "Vector3d.h"
-#include "Vector3i.h"
-
-Vector3f::Vector3f( const Vector3d & v )
- : x( (float)v.x )
- , y( (float)v.y )
- , z( (float)v.z )
-{
-}
-
-Vector3f::Vector3f( const Vector3d * v )
- : x( (float)v->x )
- , y( (float)v->y )
- , z( (float)v->z )
-{
-}
-
-Vector3f::Vector3f( const Vector3i & v )
- : x( (float)v.x )
- , y( (float)v.y )
- , z( (float)v.z )
-{
-}
-
-Vector3f::Vector3f( const Vector3i * v )
- : x( (float)v->x )
- , y( (float)v->y )
- , z( (float)v->z )
-{
-} \ No newline at end of file
diff --git a/src/Vector3f.h b/src/Vector3f.h
deleted file mode 100644
index adb154ad7..000000000
--- a/src/Vector3f.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3i;
-class Vector3d;
-class Vector3f // tolua_export
-{ // tolua_export
-public: // tolua_export
- Vector3f( const Vector3d & v ); // tolua_export
- Vector3f( const Vector3d * v ); // tolua_export
- Vector3f( const Vector3i & v ); // tolua_export
- Vector3f( const Vector3i * v ); // tolua_export
-
-
- Vector3f() : x(0), y(0), z(0) {} // tolua_export
- Vector3f(float a_x, float a_y, float a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export
-
- inline void Set(float a_x, float a_y, float a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export
- inline void Normalize() { float l = 1.0f / Length(); x *= l; y *= l; z *= l; } // tolua_export
- inline Vector3f NormalizeCopy() const { float l = 1.0f / Length(); return Vector3f( x * l, y * l, z * l ); }// tolua_export
- inline void NormalizeCopy(Vector3f & a_V) const { float l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } // tolua_export
- inline float Length() const { return (float)sqrtf( x * x + y * y + z * z ); } // tolua_export
- inline float SqrLength() const { return x * x + y * y + z * z; } // tolua_export
- inline float Dot( const Vector3f & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } // tolua_export
- inline Vector3f Cross( const Vector3f & v ) const { return Vector3f( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } // tolua_export
-
- inline bool Equals( const Vector3f & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export
-
- void operator += ( const Vector3f& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3f* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3f& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3f* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( float a_f ) { x *= a_f; y *= a_f; z *= a_f; }
- void operator *= ( Vector3f* a_V ) { x *= a_V->x; y *= a_V->y; z *= a_V->z; }
- void operator *= ( const Vector3f& a_V ) { x *= a_V.x; y *= a_V.y; z *= a_V.z; }
-
- Vector3f operator + ( const Vector3f& v2 ) const { return Vector3f( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
- Vector3f operator + ( const Vector3f* v2 ) const { return Vector3f( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
- Vector3f operator - ( const Vector3f& v2 ) const { return Vector3f( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
- Vector3f operator - ( const Vector3f* v2 ) const { return Vector3f( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
- Vector3f operator * ( const float f ) const { return Vector3f( x * f, y * f, z * f ); } // tolua_export
- Vector3f operator * ( const Vector3f& v2 ) const { return Vector3f( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
-
- float x, y, z; // tolua_export
-
-};// tolua_export
diff --git a/src/Vector3i.cpp b/src/Vector3i.cpp
deleted file mode 100644
index 4ce1e2cf3..000000000
--- a/src/Vector3i.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3i.h"
-#include "Vector3d.h"
-
-
-
-
-
-Vector3i::Vector3i( const Vector3d & v )
- : x( (int)v.x )
- , y( (int)v.y )
- , z( (int)v.z )
-{
-} \ No newline at end of file
diff --git a/src/Vector3i.h b/src/Vector3i.h
deleted file mode 100644
index 7d726a7b3..000000000
--- a/src/Vector3i.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3d;
-class Vector3i // tolua_export
-{ // tolua_export
-public: // tolua_export
- Vector3i( const Vector3d & v ); // tolua_export
-
- Vector3i() : x(0), y(0), z(0) {} // tolua_export
- Vector3i(int a_x, int a_y, int a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export
-
- inline void Set(int a_x, int a_y, int a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export
- inline float Length() const { return sqrtf( (float)( x * x + y * y + z * z) ); } // tolua_export
- inline int SqrLength() const { return x * x + y * y + z * z; } // tolua_export
-
- inline bool Equals( const Vector3i & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export
- inline bool Equals( const Vector3i * v ) const { return (x == v->x && y == v->y && z == v->z ); } // tolua_export
-
- void operator += ( const Vector3i& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3i* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3i& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3i* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( int a_f ) { x *= a_f; y *= a_f; z *= a_f; }
-
- friend Vector3i operator + ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); }
- friend Vector3i operator + ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x + v2->x, v1.y + v2->y, v1.z + v2->z ); }
- friend Vector3i operator - ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); }
- friend Vector3i operator - ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x - v2->x, v1.y - v2->y, v1.z - v2->z ); }
- friend Vector3i operator - ( const Vector3i* v1, Vector3i& v2 ) { return Vector3i( v1->x - v2.x, v1->y - v2.y, v1->z - v2.z ); }
- friend Vector3i operator * ( const Vector3i& v, const int f ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
- friend Vector3i operator * ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ); }
- friend Vector3i operator * ( const int f, const Vector3i& v ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
- friend bool operator < ( const Vector3i& v1, const Vector3i& v2 ) { return (v1.x<v2.x)||(v1.x==v2.x && v1.y<v2.y)||(v1.x==v2.x && v1.y == v2.y && v1.z<v2.z); }
-
- int x, y, z; // tolua_export
-}; // tolua_export
-
-typedef std::list<Vector3i> cVector3iList;
-typedef std::vector<Vector3i> cVector3iArray;
-
-
-
-
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index e88de5947..402cd3035 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -127,6 +127,7 @@ bool cWebAdmin::Start(void)
// Initialize the WebAdmin template script and load the file
m_TemplateScript.Create();
+ m_TemplateScript.RegisterAPILibs();
if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua"))
{
LOGWARN("Could not load WebAdmin template \"%s\", using default template.", FILE_IO_PREFIX "webadmin/template.lua");
diff --git a/src/World.cpp b/src/World.cpp
index 88cc19559..e39a605bb 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -34,6 +34,7 @@
#include "Simulator/NoopRedstoneSimulator.h"
#include "Simulator/SandSimulator.h"
#include "Simulator/IncrementalRedstoneSimulator.h"
+#include "Simulator/VanillaFluidSimulator.h"
#include "Simulator/VaporizeFluidSimulator.h"
// Mobs:
@@ -45,7 +46,6 @@
#include "Generating/Trees.h"
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
-#include "Vector3d.h"
#include "Tracer.h"
@@ -60,9 +60,6 @@
-/// Up to this many m_SpreadQueue elements are handled each world tick
-const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
-
const int TIME_SUNSET = 12000;
const int TIME_NIGHT_START = 13187;
const int TIME_NIGHT_END = 22812;
@@ -102,7 +99,7 @@ protected:
{
for (;;)
{
- LOG("%d chunks to load, %d chunks to generate",
+ LOG("" SIZE_T_FMT " chunks to load, %d chunks to generate",
m_World->GetStorage().GetLoadQueueLength(),
m_World->GetGenerator().GetQueueLength()
);
@@ -154,7 +151,7 @@ protected:
{
for (;;)
{
- LOG("%d chunks remaining to light", m_Lighting->GetQueueLength()
+ LOG("" SIZE_T_FMT " chunks remaining to light", m_Lighting->GetQueueLength()
);
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
@@ -250,8 +247,6 @@ cWorld::cWorld(const AString & a_WorldName) :
m_SkyDarkness(0),
m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
- m_bCommandBlocksEnabled(false),
- m_bUseChatPrefixes(true),
m_Scoreboard(this),
m_MapManager(this),
m_GeneratorCallbacks(*this),
@@ -264,8 +259,6 @@ cWorld::cWorld(const AString & a_WorldName) :
// Load the scoreboard
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Load();
-
- m_MapManager.LoadMapData();
}
@@ -325,8 +318,8 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
}
default:
{
- LOGWARNING("Missing default weather interval for weather %d.", a_Weather);
- return 1200;
+ LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
+ return -1;
}
} // switch (Weather)
}
@@ -348,7 +341,7 @@ void cWorld::SetWeather(eWeather a_NewWeather)
m_WeatherInterval = GetDefaultWeatherInterval(a_NewWeather);
// The weather can't be found:
- if (m_WeatherInterval == 1200)
+ if (m_WeatherInterval < 0)
{
return;
}
@@ -564,29 +557,33 @@ void cWorld::Start(void)
m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ);
}
- m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
- m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
- m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
- m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
- m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
- m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
- m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
- m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
- m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
- m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
- m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
- m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
- m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
- m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
- m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
- m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
- m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
- m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
- m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
- m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
- m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
-
- m_GameMode = (eGameMode)IniFile.GetValueSetI("General", "Gamemode", m_GameMode);
+ m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
+ m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
+ m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
+ m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
+ m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
+ m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
+ m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
+ m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
+ m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
+ m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
+ m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
+ m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
+ m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
+ m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
+ m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
+ m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
+ m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
+ int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone);
+ m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
+ m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
+ m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
+ m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
+ int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode);
+
+ // Adjust the enum-backed variables into their respective bounds:
+ m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure);
+ m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll);
// Load allowed mobs:
const char * DefaultMonsters = "";
@@ -652,13 +649,13 @@ void cWorld::Start(void)
m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfAmbient, 0));
m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfWater, 0));
+ m_MapManager.LoadMapData();
// Save any changes that the defaults may have done to the ini file:
if (!IniFile.WriteFile(m_IniFileName))
{
LOGWARNING("Could not write world config to %s", m_IniFileName.c_str());
}
-
}
@@ -1199,9 +1196,18 @@ bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
-bool cWorld::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
+{
+ return m_ChunkMap->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
+bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{
- return m_ChunkMap->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+ return m_ChunkMap->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
@@ -1718,12 +1724,15 @@ 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, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
+void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
- UNUSED(a_InitialVelocityCoeff);
- cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec);
+ cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
TNT->Initialize(this);
- // TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff
+ TNT->SetSpeed(
+ a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
+ a_InitialVelocityCoeff * 2,
+ a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1)
+ );
}
@@ -1750,7 +1759,7 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cWorld::DigBlock(int a_X, int a_Y, int a_Z)
{
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z));
+ cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z));
cChunkInterface ChunkInterface(GetChunkMap());
Handler->OnDestroyed(ChunkInterface, *this, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
@@ -2446,14 +2455,14 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit,
{
cTracer LineOfSight(this);
- float ClosestDistance = a_SightLimit;
- cPlayer* ClosestPlayer = NULL;
+ double ClosestDistance = a_SightLimit;
+ cPlayer * ClosestPlayer = NULL;
cCSLock Lock(m_CSPlayers);
for (cPlayerList::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Vector3f Pos = (*itr)->GetPosition();
- float Distance = (Pos - a_Pos).Length();
+ double Distance = (Pos - a_Pos).Length();
if (Distance < ClosestDistance)
{
@@ -2972,9 +2981,9 @@ 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 Vector3d * a_Speed)
+int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
{
- cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
+ cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)
{
return -1;
@@ -2997,18 +3006,18 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr)
{
- size_t LastSpace = a_Text.find_last_of(" "); //Find the position of the last space
+ size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space
- std::string LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); //Find the last word
- std::string PlayerName ((*itr)->GetName());
- std::size_t Found = PlayerName.find(LastWord); //Try to find last word in playername
+ AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word
+ AString PlayerName ((*itr)->GetName());
+ size_t Found = PlayerName.find(LastWord); // Try to find last word in playername
- if (Found!=0)
+ if (Found == AString::npos)
{
- continue; //No match
+ continue; // No match
}
- a_Results.push_back((*itr)->GetName()); //Match!
+ a_Results.push_back(PlayerName); // Match!
}
}
@@ -3055,8 +3064,8 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
if (SimulatorName.empty())
{
- LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Floody\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
- SimulatorName = "Floody";
+ LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Vanilla\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
+ SimulatorName = "Vanilla";
}
cFluidSimulator * res = NULL;
@@ -3080,15 +3089,24 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
}
else
{
- if (NoCaseCompare(SimulatorName, "floody") != 0)
- {
- // The simulator name doesn't match anything we have, issue a warning:
- LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Floody\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
- }
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
- res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+
+ if (NoCaseCompare(SimulatorName, "floody") == 0)
+ {
+ res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
+ else if (NoCaseCompare(SimulatorName, "vanilla") == 0)
+ {
+ res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
+ else
+ {
+ // The simulator name doesn't match anything we have, issue a warning:
+ LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Vanilla\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
+ res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
}
m_SimulatorManager->RegisterSimulator(res, Rate);
diff --git a/src/World.h b/src/World.h
index 27f1482e5..b3ee94a27 100644
--- a/src/World.h
+++ b/src/World.h
@@ -14,8 +14,7 @@
#include "ChunkMap.h"
#include "WorldStorage/WorldStorage.h"
#include "Generating/ChunkGenerator.h"
-#include "Vector3i.h"
-#include "Vector3f.h"
+#include "Vector3.h"
#include "ChunkSender.h"
#include "Defines.h"
#include "LightingThread.h"
@@ -44,6 +43,7 @@ class cWorldGenerator; // The generator that actually generates the chunks for
class cChunkGenerator; // The thread responsible for generating chunks
class cChestEntity;
class cDispenserEntity;
+class cFlowerPotEntity;
class cFurnaceEntity;
class cNoteEntity;
class cMobHeadEntity;
@@ -60,7 +60,8 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
@@ -124,22 +125,24 @@ public:
// tolua_begin
int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
- virtual Int64 GetWorldAge(void) const { return m_WorldAge; }
- virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; }
+
+ virtual Int64 GetWorldAge (void) const { return m_WorldAge; } // override, cannot specify due to tolua
+ virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } // override, cannot specify due to tolua
void SetTicksUntilWeatherChange(int a_WeatherInterval)
{
m_WeatherInterval = a_WeatherInterval;
}
- void SetTimeOfDay(Int64 a_TimeOfDay)
+ virtual void SetTimeOfDay(Int64 a_TimeOfDay) // override, cannot specify due to tolua
{
m_TimeOfDay = a_TimeOfDay;
m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
BroadcastTimeUpdate();
}
- /** Returns the default weather interval for the specific weather type */
+ /** Returns the default weather interval for the specific weather type.
+ Returns -1 for any unknown weather. */
int GetDefaultWeatherInterval(eWeather a_Weather);
/** Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */
@@ -189,35 +192,35 @@ public:
void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL);
// tolua_end
- void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
- void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
- void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
- void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export
- void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
- void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
- void BroadcastScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
- void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
- void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
- void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
- void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
- void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
- virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
- void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
-
- virtual cBroadcastInterface & GetBroadcastManager()
+ void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
+ void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
+ void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) override;
+ void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
+ void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
+ void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
+ void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
+ void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
+ void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
+ void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
+ virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
+
+ virtual cBroadcastInterface & GetBroadcastManager(void) override
{
return *this;
}
@@ -271,7 +274,7 @@ public:
void RemovePlayer( cPlayer* a_Player );
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
- bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+ virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS <<
/** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
@@ -363,7 +366,7 @@ public:
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
/** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */
- virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
+ virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) override;
// tolua_begin
@@ -442,7 +445,7 @@ public:
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
/** 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, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
// tolua_end
@@ -454,7 +457,7 @@ public:
// tolua_begin
bool DigBlock (int a_X, int a_Y, int a_Z);
- void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
+ virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); // override, cannot specify due to tolua
double GetSpawnX(void) const { return m_SpawnX; }
double GetSpawnY(void) const { return m_SpawnY; }
@@ -494,18 +497,18 @@ public:
/** Does an explosion with the specified strength at the specified coordinate
a_SourceData exact type depends on the a_Source:
- | esOther | void * |
- | esPrimedTNT | cTNTEntity * |
- | esMonster | cMonster * |
- | esBed | cVector3i * |
- | esEnderCrystal | Vector3i * |
- | esGhastFireball | cGhastFireball * |
- | esWitherSkullBlack | TBD |
- | esWitherSkullBlue | TBD |
- | esWitherBirth | TBD |
- | esPlugin | void * |
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esMonster | cMonster * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | cGhastFireball * |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | cMonster * |
+ | esPlugin | void * |
*/
- virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
+ virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export // override, cannot specify due to tolua
/** 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); // Exported in ManualBindings.cpp
@@ -530,10 +533,13 @@ public:
/** 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); // Exported in ManualBindings.cpp
-
+
/** 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 DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); // Exported in ManualBindings.cpp
-
+ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /** 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); // Exported in ManualBindings.cpp
+
/** 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); // Exported in ManualBindings.cpp
@@ -599,6 +605,9 @@ public:
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; }
+ eShrapnelLevel GetTNTShrapnelLevel(void) const { return m_TNTShrapnelLevel; }
+ void SetTNTShrapnelLevel(eShrapnelLevel a_Flag) { m_TNTShrapnelLevel = a_Flag; }
+
bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; }
void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; }
@@ -637,9 +646,9 @@ public:
// Various queues length queries (cannot be const, they lock their CS):
inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
- inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
- inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
- inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
+ inline size_t GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
+ inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
+ inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
void InitializeSpawn(void);
@@ -698,11 +707,11 @@ 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, cMonster::eType a_MonsterType); // tolua_export
+ virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export // override, cannot specify due to tolua
int SpawnMobFinalize(cMonster* a_Monster);
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
- int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
@@ -856,6 +865,11 @@ private:
/** Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions */
bool m_bUseChatPrefixes;
+
+ /** The level of DoExplosionAt() projecting random affected blocks as FallingBlock entities
+ See the eShrapnelLevel enumeration for details
+ */
+ eShrapnelLevel m_TNTShrapnelLevel;
cChunkGenerator m_Generator;
diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp
index 8f80c3f75..be25fd1a4 100644
--- a/src/WorldStorage/FastNBT.cpp
+++ b/src/WorldStorage/FastNBT.cpp
@@ -506,22 +506,18 @@ void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, si
{
TagCommon(a_Name, TAG_IntArray);
Int32 len = htonl(a_NumElements);
+ size_t cap = m_Result.capacity();
+ size_t size = m_Result.length();
+ if ((cap - size) < (4 + a_NumElements * 4))
+ {
+ m_Result.reserve(size + 4 + (a_NumElements * 4));
+ }
m_Result.append((const char *)&len, 4);
-#if defined(ANDROID_NDK)
- // Android has alignment issues - cannot byteswap (htonl) an int that is not 32-bit-aligned, which happens in the regular version
for (size_t i = 0; i < a_NumElements; i++)
{
int Element = htonl(a_Value[i]);
m_Result.append((const char *)&Element, 4);
}
-#else
- int * Elements = (int *)(m_Result.data() + m_Result.size());
- m_Result.append(a_NumElements * 4, (char)0);
- for (size_t i = 0; i < a_NumElements; i++)
- {
- Elements[i] = htonl(a_Value[i]);
- }
-#endif
}
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index 49f97c458..1b8b09c21 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -106,6 +106,10 @@ public:
/** Parses and contains the parsed data
Also implements data accessor functions for tree traversal and value getters
The data pointer passed in the constructor is assumed to be valid throughout the object's life. Care must be taken not to initialize from a temporary.
+The parser decomposes the input data into a tree of tags that is stored as an array of cFastNBTTag items,
+and accessing the tree is done by using the array indices for tags. Each tag stores the indices for its parent,
+first child, last child, prev sibling and next sibling, a value of -1 indicates that the indice is not valid.
+Each primitive tag also stores the length of the contained data, in bytes.
*/
class cParsedNBT
{
@@ -114,13 +118,32 @@ public:
bool IsValid(void) const {return m_IsValid; }
+ /** Returns the root tag of the hierarchy. */
int GetRoot(void) const {return 0; }
+
+ /** Returns the first child of the specified tag, or -1 if none / not applicable. */
int GetFirstChild (int a_Tag) const { return m_Tags[a_Tag].m_FirstChild; }
+
+ /** Returns the last child of the specified tag, or -1 if none / not applicable. */
int GetLastChild (int a_Tag) const { return m_Tags[a_Tag].m_LastChild; }
+
+ /** Returns the next sibling of the specified tag, or -1 if none. */
int GetNextSibling(int a_Tag) const { return m_Tags[a_Tag].m_NextSibling; }
+
+ /** Returns the previous sibling of the specified tag, or -1 if none. */
int GetPrevSibling(int a_Tag) const { return m_Tags[a_Tag].m_PrevSibling; }
- int GetDataLength (int a_Tag) const { return m_Tags[a_Tag].m_DataLength; }
+
+ /** Returns the length of the tag's data, in bytes.
+ Not valid for Compound or List tags! */
+ int GetDataLength (int a_Tag) const
+ {
+ ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
+ ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound);
+ return m_Tags[a_Tag].m_DataLength;
+ }
+ /** Returns the data stored in this tag.
+ Not valid for Compound or List tags! */
const char * GetData(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type != TAG_List);
@@ -128,55 +151,64 @@ public:
return m_Data + m_Tags[a_Tag].m_DataStart;
}
+ /** Returns the direct child tag of the specified name, or -1 if no such tag. */
int FindChildByName(int a_Tag, const AString & a_Name) const
{
return FindChildByName(a_Tag, a_Name.c_str(), a_Name.length());
}
+ /** Returns the direct child tag of the specified name, or -1 if no such tag. */
int FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLength = 0) const;
- int FindTagByPath (int a_Tag, const AString & a_Path) const;
+
+ /** Returns the child tag of the specified path (Name1\Name2\Name3...), or -1 if no such tag. */
+ int FindTagByPath(int a_Tag, const AString & a_Path) const;
eTagType GetType(int a_Tag) const { return m_Tags[a_Tag].m_Type; }
- /// Returns the children type for a list tag; undefined on other tags. If list empty, returns TAG_End
+ /** Returns the children type for a List tag; undefined on other tags. If list empty, returns TAG_End. */
eTagType GetChildrenType(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_List);
return (m_Tags[a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[m_Tags[a_Tag].m_FirstChild].m_Type;
}
+ /** Returns the value stored in a Byte tag. Not valid for any other tag type. */
inline unsigned char GetByte(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Byte);
return (unsigned char)(m_Data[m_Tags[a_Tag].m_DataStart]);
}
+ /** Returns the value stored in a Short tag. Not valid for any other tag type. */
inline Int16 GetShort(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Short);
return GetBEShort(m_Data + m_Tags[a_Tag].m_DataStart);
}
+ /** Returns the value stored in an Int tag. Not valid for any other tag type. */
inline Int32 GetInt(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Int);
return GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
}
+ /** Returns the value stored in a Long tag. Not valid for any other tag type. */
inline Int64 GetLong(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Long);
return NetworkToHostLong8(m_Data + m_Tags[a_Tag].m_DataStart);
}
+ /** Returns the value stored in a Float tag. Not valid for any other tag type. */
inline float GetFloat(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_Float);
// Cause a compile-time error if sizeof(float) != 4
// If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats
- char Check1[5 - sizeof(float)]; // sizeof(float) <= 4
- char Check2[sizeof(float) - 3]; // sizeof(float) >= 4
+ char Check1[5 - sizeof(float)]; // Fails if sizeof(float) > 4
+ char Check2[sizeof(float) - 3]; // Fails if sizeof(float) < 4
UNUSED(Check1);
UNUSED(Check2);
@@ -186,12 +218,21 @@ public:
return f;
}
+ /** Returns the value stored in a Double tag. Not valid for any other tag type. */
inline double GetDouble(int a_Tag) const
{
+ // Cause a compile-time error if sizeof(double) != 8
+ // If your platform produces a compiler error here, you'll need to add code that manually decodes 64-bit doubles
+ char Check1[9 - sizeof(double)]; // Fails if sizeof(double) > 8
+ char Check2[sizeof(double) - 7]; // Fails if sizeof(double) < 8
+ UNUSED(Check1);
+ UNUSED(Check2);
+
ASSERT(m_Tags[a_Tag].m_Type == TAG_Double);
return NetworkToHostDouble8(m_Data + m_Tags[a_Tag].m_DataStart);
}
+ /** Returns the value stored in a String tag. Not valid for any other tag type. */
inline AString GetString(int a_Tag) const
{
ASSERT(m_Tags[a_Tag].m_Type == TAG_String);
@@ -200,6 +241,7 @@ public:
return res;
}
+ /** Returns the tag's name. For tags that are not named, returns an empty string. */
inline AString GetName(int a_Tag) const
{
AString res;
@@ -267,7 +309,7 @@ protected:
eTagType m_ItemType; // for TAG_List, the element type
} ;
- static const int MAX_STACK = 50; // Highliy doubtful that an NBT would be constructed this many levels deep
+ static const int MAX_STACK = 50; // Highly doubtful that an NBT would be constructed this many levels deep
// These two fields emulate a stack. A raw array is used due to speed issues - no reallocations are allowed.
sParent m_Stack[MAX_STACK];
diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
new file mode 100644
index 000000000..744fc731f
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -0,0 +1,262 @@
+
+#include "Globals.h"
+#include "FireworksSerializer.h"
+#include "WorldStorage/FastNBT.h"
+
+
+
+
+
+void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
+{
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ a_Writer.BeginCompound("Fireworks");
+ a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
+ a_Writer.BeginList("Explosions", TAG_Compound);
+ a_Writer.BeginCompound("");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ if (!a_FireworkItem.m_Colours.empty())
+ {
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ }
+ if (!a_FireworkItem.m_FadeColours.empty())
+ {
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ }
+ a_Writer.EndCompound();
+ a_Writer.EndList();
+ a_Writer.EndCompound();
+ break;
+ }
+ case E_ITEM_FIREWORK_STAR:
+ {
+ a_Writer.BeginCompound("Explosion");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ if (!a_FireworkItem.m_Colours.empty())
+ {
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ }
+ if (!a_FireworkItem.m_FadeColours.empty())
+ {
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ }
+ a_Writer.EndCompound();
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
+{
+ if (a_TagIdx < 0)
+ {
+ return;
+ }
+
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
+ {
+ eTagType TagType = a_NBT.GetType(explosiontag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Flicker")
+ {
+ a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Trail")
+ {
+ a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Type")
+ {
+ a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
+ }
+ }
+ else if (TagType == TAG_IntArray)
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Colors")
+ {
+ // Divide by four as data length returned in bytes
+ int DataLength = a_NBT.GetDataLength(explosiontag);
+ // round to the next highest multiple of four
+ DataLength -= DataLength % 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const char * ColourData = (a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ {
+ a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
+ }
+ }
+ else if (ExplosionName == "FadeColors")
+ {
+ int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ // round to the next highest multiple of four
+ DataLength -= DataLength % 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const char * FadeColourData = (a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ {
+ a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
+ }
+ }
+ }
+ }
+ break;
+ }
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
+ {
+ eTagType TagType = a_NBT.GetType(fireworkstag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ if (a_NBT.GetName(fireworkstag) == "Flight")
+ {
+ a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
+ }
+ }
+ else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
+ {
+ int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
+ if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
+ {
+ ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
+ }
+ }
+ }
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
+{
+ /*
+ Colours are supposed to be calculated via: R << 16 + G << 8 + B
+ However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
+ Therefore, here is a list of numbers gotten via the Protocol Proxy
+ */
+
+ switch (a_DyeMeta)
+ {
+ case E_META_DYE_BLACK: return 0x1E1B1B;
+ case E_META_DYE_RED: return 0xB3312C;
+ case E_META_DYE_GREEN: return 0x3B511A;
+ case E_META_DYE_BROWN: return 0x51301A;
+ case E_META_DYE_BLUE: return 0x253192;
+ case E_META_DYE_PURPLE: return 0x7B2FBE;
+ case E_META_DYE_CYAN: return 0x287697;
+ case E_META_DYE_LIGHTGRAY: return 0xABABAB;
+ case E_META_DYE_GRAY: return 0x434343;
+ case E_META_DYE_PINK: return 0xD88198;
+ case E_META_DYE_LIGHTGREEN: return 0x41CD34;
+ case E_META_DYE_YELLOW: return 0xDECF2A;
+ case E_META_DYE_LIGHTBLUE: return 0x6689D3;
+ case E_META_DYE_MAGENTA: return 0xC354CD;
+ case E_META_DYE_ORANGE: return 0xEB8844;
+ case E_META_DYE_WHITE: return 0xF0F0F0;
+ default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
+ }
+}
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
new file mode 100644
index 000000000..cbc544a14
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -0,0 +1,92 @@
+
+// FireworksSerializer.h
+
+// Declares the cFireworkItem class representing a firework or firework star
+
+
+
+
+
+#pragma once
+
+#include "Defines.h"
+
+class cFastNBTWriter;
+class cParsedNBT;
+
+
+
+
+
+class cFireworkItem
+{
+public:
+ cFireworkItem(void) :
+ m_HasFlicker(false),
+ m_HasTrail(false),
+ m_Type(0),
+ m_FlightTimeInTicks(0)
+ {
+ }
+
+ inline void CopyFrom(const cFireworkItem & a_Item)
+ {
+ m_FlightTimeInTicks = a_Item.m_FlightTimeInTicks;
+ m_HasFlicker = a_Item.m_HasFlicker;
+ m_HasTrail = a_Item.m_HasTrail;
+ m_Type = a_Item.m_Type;
+ m_Colours = a_Item.m_Colours;
+ m_FadeColours = a_Item.m_FadeColours;
+ }
+
+ inline void EmptyData(void)
+ {
+ m_FlightTimeInTicks = 0;
+ m_HasFlicker = false;
+ m_Type = 0;
+ m_HasTrail = false;
+ m_Colours.clear();
+ m_FadeColours.clear();
+ }
+
+ inline bool IsEqualTo(const cFireworkItem & a_Item) const
+ {
+ return
+ (
+ (m_FlightTimeInTicks == a_Item.m_FlightTimeInTicks) &&
+ (m_HasFlicker == a_Item.m_HasFlicker) &&
+ (m_HasTrail == a_Item.m_HasTrail) &&
+ (m_Type == a_Item.m_Type) &&
+ (m_Colours == a_Item.m_Colours) &&
+ (m_FadeColours == a_Item.m_FadeColours)
+ );
+ }
+
+ /** Writes firework NBT data to a Writer object */
+ static void WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type);
+
+ /** Reads NBT data from a NBT object and populates a FireworkItem with it */
+ static void ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type);
+
+ /** Converts the firework's vector of colours into a string of values separated by a semicolon */
+ static AString ColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework colours and populates a FireworkItem with it */
+ static void ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Converts the firework's vector of fade colours into a string of values separated by a semicolon */
+ static AString FadeColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework fade colours and populates a FireworkItem with it */
+ static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Returns a colour code for fireworks used by the network code */
+ static int GetVanillaColourCodeFromDye(short a_DyeMeta);
+
+ bool m_HasFlicker;
+ bool m_HasTrail;
+ NIBBLETYPE m_Type;
+ short m_FlightTimeInTicks;
+ std::vector<int> m_Colours;
+ std::vector<int> m_FadeColours;
+};
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index a4a0aab57..df72d1cc9 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -141,7 +141,11 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
{
eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
- ASSERT(Dimension == m_Map->m_World->GetDimension());
+ if (Dimension != m_Map->m_World->GetDimension())
+ {
+ // TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c.
+ return false;
+ }
}
CurrLine = a_NBT.FindChildByName(Data, "width");
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index c1c659b36..415693ae2 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -20,13 +20,19 @@
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../Entities/Entity.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
#include "../Mobs/Monster.h"
#include "../Mobs/Bat.h"
@@ -38,6 +44,7 @@
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
#include "../Mobs/Villager.h"
+#include "../Mobs/Wither.h"
#include "../Mobs/Wolf.h"
#include "../Mobs/Zombie.h"
@@ -90,11 +97,19 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin
}
// Write the enchantments:
- if (!a_Item.m_Enchantments.IsEmpty())
+ if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
{
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
m_Writer.BeginCompound("tag");
- EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ }
m_Writer.EndCompound();
}
@@ -275,6 +290,19 @@ void cNBTChunkSerializer::AddMobHeadEntity(cMobHeadEntity * a_MobHead)
+void cNBTChunkSerializer::AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot)
+{
+ m_Writer.BeginCompound("");
+ AddBasicTileEntity(a_FlowerPot, "FlowerPot");
+ m_Writer.AddInt ("Item", (Int32) a_FlowerPot->GetItem().m_ItemType);
+ m_Writer.AddInt ("Data", (Int32) a_FlowerPot->GetItem().m_ItemDamage);
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_ClassName)
{
m_Writer.AddString("id", a_ClassName);
@@ -309,6 +337,17 @@ void cNBTChunkSerializer::AddBoatEntity(cBoat * a_Boat)
+void cNBTChunkSerializer::AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_EnderCrystal, "EnderCrystal");
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
{
m_Writer.BeginCompound("");
@@ -396,7 +435,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
case cMonster::mtSquid: EntityClass = "Squid"; break;
case cMonster::mtVillager: EntityClass = "Villager"; break;
case cMonster::mtWitch: EntityClass = "Witch"; break;
- case cMonster::mtWither: EntityClass = "Wither"; break;
+ case cMonster::mtWither: EntityClass = "WitherBoss"; break;
case cMonster::mtWolf: EntityClass = "Wolf"; break;
case cMonster::mtZombie: EntityClass = "Zombie"; break;
case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break;
@@ -475,6 +514,11 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
break;
}
+ case cMonster::mtWither:
+ {
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ break;
+ }
case cMonster::mtWolf:
{
m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner());
@@ -503,8 +547,8 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
- m_Writer.AddShort("Health", a_Pickup->GetHealth());
- m_Writer.AddShort("Age", a_Pickup->GetAge());
+ m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
+ m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound();
}
@@ -569,6 +613,66 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
+void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
+{
+ m_Writer.AddByte("Direction", (unsigned char)a_Hanging->GetDirection());
+ m_Writer.AddInt("TileX", a_Hanging->GetTileX());
+ m_Writer.AddInt("TileY", a_Hanging->GetTileY());
+ m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
+ switch (a_Hanging->GetDirection())
+ {
+ case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ }
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_TNT, "PrimedTnt");
+ m_Writer.AddByte("Fuse", (unsigned char)a_TNT->GetFuseTicks());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddExpOrbEntity(cExpOrb * a_ExpOrb)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_ExpOrb, "XPOrb");
+ m_Writer.AddShort("Health", (Int16)(unsigned char)a_ExpOrb->GetHealth());
+ m_Writer.AddShort("Age", (Int16)a_ExpOrb->GetAge());
+ m_Writer.AddShort("Value", (Int16)a_ExpOrb->GetReward());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_ItemFrame, "ItemFrame");
+ AddHangingEntity(a_ItemFrame);
+ AddItem(a_ItemFrame->GetItem(), -1, "Item");
+ m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetRotation());
+ m_Writer.AddFloat("ItemDropChance", 1.0F);
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -643,14 +747,15 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
switch (a_Entity->GetEntityType())
{
case cEntity::etBoat: AddBoatEntity ((cBoat *) a_Entity); break;
+ case cEntity::etEnderCrystal: AddEnderCrystalEntity((cEnderCrystal *) a_Entity); break;
case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break;
case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
- case cEntity::etTNT: /* TODO */ break;
- case cEntity::etExpOrb: /* TODO */ break;
- case cEntity::etItemFrame: /* TODO */ break;
+ 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::etPlayer: return; // Players aren't saved into the world
default:
@@ -687,6 +792,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
+ case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 5f9e16ed1..51d104970 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -24,12 +24,14 @@ class cChestEntity;
class cCommandBlockEntity;
class cDispenserEntity;
class cDropperEntity;
+class cEnderCrystal;
class cFurnaceEntity;
class cHopperEntity;
class cJukeboxEntity;
class cNoteEntity;
class cSignEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cFallingBlock;
class cMinecart;
class cMinecartWithChest;
@@ -40,6 +42,10 @@ class cMonster;
class cPickup;
class cItemGrid;
class cProjectileEntity;
+class cTNTEntity;
+class cExpOrb;
+class cHangingEntity;
+class cItemFrame;
@@ -96,15 +102,21 @@ protected:
void AddSignEntity (cSignEntity * a_Sign);
void AddMobHeadEntity (cMobHeadEntity * a_MobHead);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
+ void AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot);
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
void AddBoatEntity (cBoat * a_Boat);
+ void AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal);
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
+ void AddHangingEntity (cHangingEntity * a_Hanging);
+ void AddTNTEntity (cTNTEntity * a_TNT);
+ void AddExpOrbEntity (cExpOrb * a_ExpOrb);
+ void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index 45fd967bd..9d594a084 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -1,10 +1,51 @@
+// SchematicFileSerializer.cpp
+
+// Implements the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
+
#include "Globals.h"
#include "OSSupport/GZipFile.h"
#include "FastNBT.h"
-
#include "SchematicFileSerializer.h"
+#include "../StringCompression.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+static class cSchematicStringSelfTest
+{
+public:
+ cSchematicStringSelfTest(void)
+ {
+ cBlockArea ba;
+ ba.Create(21, 256, 21);
+ ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1);
+ AString Schematic;
+ if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic))
+ {
+ assert_test(!"Schematic failed to save!");
+ }
+ cBlockArea ba2;
+ if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic))
+ {
+ assert_test(!"Schematic failed to load!");
+ }
+ }
+} g_SelfTest;
+
+#endif
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSchematicFileSerializer:
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
{
@@ -40,48 +81,51 @@ bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, c
-bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
+bool cSchematicFileSerializer::LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData)
{
- cFastNBTWriter Writer("Schematic");
- Writer.AddShort("Width", a_BlockArea.m_SizeX);
- Writer.AddShort("Height", a_BlockArea.m_SizeY);
- Writer.AddShort("Length", a_BlockArea.m_SizeZ);
- Writer.AddString("Materials", "Alpha");
- if (a_BlockArea.HasBlockTypes())
- {
- Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
- }
- else
+ // Uncompress the data:
+ AString UngzippedData;
+ if (UncompressStringGZIP(a_SchematicData.data(), a_SchematicData.size(), UngzippedData) != Z_OK)
{
- AString Dummy(a_BlockArea.GetBlockCount(), 0);
- Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
+ LOG("%s: Cannot unGZip the schematic data.", __FUNCTION__);
+ return false;
}
- if (a_BlockArea.HasBlockMetas())
+
+ // Parse the NBT:
+ cParsedNBT NBT(UngzippedData.data(), UngzippedData.size());
+ if (!NBT.IsValid())
{
- Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
+ LOG("%s: Cannot parse the NBT in the schematic data.", __FUNCTION__);
+ return false;
}
- else
+
+ return LoadFromSchematicNBT(a_BlockArea, NBT);
+}
+
+
+
+
+
+bool cSchematicFileSerializer::SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName)
+{
+ // Serialize into NBT data:
+ AString NBT = SaveToSchematicNBT(a_BlockArea);
+ if (NBT.empty())
{
- AString Dummy(a_BlockArea.GetBlockCount(), 0);
- Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
+ LOG("%s: Cannot serialize the area into an NBT representation for file \"%s\".", __FUNCTION__, a_FileName.c_str());
+ return false;
}
- // TODO: Save entities and block entities
- Writer.BeginList("Entities", TAG_Compound);
- Writer.EndList();
- Writer.BeginList("TileEntities", TAG_Compound);
- Writer.EndList();
- Writer.Finish();
// Save to file
cGZipFile File;
if (!File.Open(a_FileName, cGZipFile::fmWrite))
{
- LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str());
+ LOG("%s: Cannot open file \"%s\" for writing.", __FUNCTION__, a_FileName.c_str());
return false;
}
- if (!File.Write(Writer.GetResult()))
+ if (!File.Write(NBT))
{
- LOG("Cannot write data to file \"%s\".", a_FileName.c_str());
+ LOG("%s: Cannot write data to file \"%s\".", __FUNCTION__, a_FileName.c_str());
return false;
}
return true;
@@ -92,6 +136,30 @@ bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, con
+bool cSchematicFileSerializer::SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out)
+{
+ // Serialize into NBT data:
+ AString NBT = SaveToSchematicNBT(a_BlockArea);
+ if (NBT.empty())
+ {
+ LOG("%s: Cannot serialize the area into an NBT representation.", __FUNCTION__);
+ return false;
+ }
+
+ // Gzip the data:
+ int res = CompressStringGZIP(NBT.data(), NBT.size(), a_Out);
+ if (res != Z_OK)
+ {
+ LOG("%s: Cannot Gzip the area data NBT representation: %d", __FUNCTION__, res);
+ return false;
+ }
+ return true;
+}
+
+
+
+
+
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT)
{
int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
@@ -142,8 +210,27 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
a_BlockArea.Clear();
a_BlockArea.SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (cBlockArea::baTypes | cBlockArea::baMetas) : cBlockArea::baTypes);
+ int TOffsetX = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetX");
+ int TOffsetY = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetY");
+ int TOffsetZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetZ");
+
+ if (
+ (TOffsetX < 0) || (TOffsetY < 0) || (TOffsetZ < 0) ||
+ (a_NBT.GetType(TOffsetX) != TAG_Int) ||
+ (a_NBT.GetType(TOffsetY) != TAG_Int) ||
+ (a_NBT.GetType(TOffsetZ) != TAG_Int)
+ )
+ {
+ // Not every schematic file has an offset, so we shoudn't give a warn message.
+ a_BlockArea.SetWEOffset(0, 0, 0);
+ }
+ else
+ {
+ a_BlockArea.SetWEOffset(a_NBT.GetInt(TOffsetX), a_NBT.GetInt(TOffsetY), a_NBT.GetInt(TOffsetZ));
+ }
+
// Copy the block types and metas:
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
{
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -155,7 +242,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
if (AreMetasPresent)
{
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
{
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -170,3 +257,49 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
+
+
+
+AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea)
+{
+ cFastNBTWriter Writer("Schematic");
+ Writer.AddShort("Width", a_BlockArea.m_Size.x);
+ Writer.AddShort("Height", a_BlockArea.m_Size.y);
+ Writer.AddShort("Length", a_BlockArea.m_Size.z);
+ Writer.AddString("Materials", "Alpha");
+ if (a_BlockArea.HasBlockTypes())
+ {
+ Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
+ }
+ else
+ {
+ AString Dummy(a_BlockArea.GetBlockCount(), 0);
+ Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
+ }
+ if (a_BlockArea.HasBlockMetas())
+ {
+ Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
+ }
+ else
+ {
+ AString Dummy(a_BlockArea.GetBlockCount(), 0);
+ Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
+ }
+
+ Writer.AddInt("WEOffsetX", a_BlockArea.m_WEOffset.x);
+ Writer.AddInt("WEOffsetY", a_BlockArea.m_WEOffset.y);
+ Writer.AddInt("WEOffsetZ", a_BlockArea.m_WEOffset.z);
+
+ // TODO: Save entities and block entities
+ Writer.BeginList("Entities", TAG_Compound);
+ Writer.EndList();
+ Writer.BeginList("TileEntities", TAG_Compound);
+ Writer.EndList();
+ Writer.Finish();
+
+ return Writer.GetResult();
+}
+
+
+
+
diff --git a/src/WorldStorage/SchematicFileSerializer.h b/src/WorldStorage/SchematicFileSerializer.h
index 9be2e5b57..05b6c74f4 100644
--- a/src/WorldStorage/SchematicFileSerializer.h
+++ b/src/WorldStorage/SchematicFileSerializer.h
@@ -1,4 +1,12 @@
+// SchematicFileSerializer.h
+
+// Declares the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
+
+
+
+
+
#pragma once
#include "../BlockArea.h"
@@ -13,17 +21,34 @@ class cParsedNBT;
+
class cSchematicFileSerializer
{
public:
- /// Loads an area from a .schematic file. Returns true if successful
+ /** Loads an area from a .schematic file. Returns true if successful. */
static bool LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
- /// Saves the area into a .schematic file. Returns true if successful
- static bool SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
+ /** Loads an area from a string containing the .schematic file data. Returns true if successful. */
+ static bool LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData);
+
+ /** Saves the area into a .schematic file. Returns true if successful. */
+ static bool SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName);
+
+ /** Saves the area into a string containing the .schematic file data.
+ Returns true if successful, false on failure. The data is stored into a_Out. */
+ static bool SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out);
private:
- /// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful.
+ /** Loads the area from a schematic file uncompressed and parsed into a NBT tree.
+ Returns true if successful. */
static bool LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT);
+
+ /** Saves the area into a NBT representation and returns the NBT data as a string.
+ Returns an empty string if failed. */
+ static AString SaveToSchematicNBT(const cBlockArea & a_BlockArea);
};
+
+
+
+
diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp
index 9b8b661c4..6c885bb45 100644
--- a/src/WorldStorage/ScoreboardSerializer.cpp
+++ b/src/WorldStorage/ScoreboardSerializer.cpp
@@ -173,13 +173,13 @@ void cScoreboardSerializer::SaveScoreboardToNBT(cFastNBTWriter & a_Writer)
a_Writer.BeginCompound("DisplaySlots");
- cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_LIST);
+ cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsList);
a_Writer.AddString("slot_0", (Objective == NULL) ? "" : Objective->GetName());
- Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_SIDEBAR);
+ Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsSidebar);
a_Writer.AddString("slot_1", (Objective == NULL) ? "" : Objective->GetName());
- Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_NAME);
+ Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsName);
a_Writer.AddString("slot_2", (Objective == NULL) ? "" : Objective->GetName());
a_Writer.EndCompound(); // DisplaySlots
@@ -280,7 +280,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name, DisplayName, Prefix, Suffix;
- bool AllowsFriendlyFire = false, CanSeeFriendlyInvisible = false;
+ bool AllowsFriendlyFire = true, CanSeeFriendlyInvisible = false;
int CurrLine = a_NBT.FindChildByName(Child, "Name");
if (CurrLine >= 0)
@@ -346,7 +346,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name = a_NBT.GetString(CurrLine);
- m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_LIST);
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::dsList);
}
CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_1");
@@ -354,7 +354,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name = a_NBT.GetString(CurrLine);
- m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_SIDEBAR);
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::dsSidebar);
}
CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_2");
@@ -362,7 +362,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name = a_NBT.GetString(CurrLine);
- m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_NAME);
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::dsName);
}
return true;
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 05332d23d..48934d074 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -25,16 +25,22 @@
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../Mobs/Monster.h"
#include "../Mobs/IncludeAllMonsters.h"
#include "../Entities/Boat.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
@@ -364,6 +370,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
{
case E_BLOCK_AIR:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
// nothing needed
break;
@@ -505,10 +512,10 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio
// The biomes stored don't match in size
return NULL;
}
- const int * BiomeData = (const int *)(a_NBT.GetData(a_TagIdx));
+ const char * BiomeData = (a_NBT.GetData(a_TagIdx));
for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++)
{
- (*a_BiomeMap)[i] = (EMCSBiome)(ntohl(BiomeData[i]));
+ (*a_BiomeMap)[i] = (EMCSBiome)(GetBEInt(&BiomeData[i * 4]));
if ((*a_BiomeMap)[i] == 0xff)
{
// Unassigned biomes
@@ -578,6 +585,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{
LoadDropperFromNBT(a_BlockEntities, a_NBT, Child);
}
+ else if (strncmp(a_NBT.GetData(sID), "FlowerPot", a_NBT.GetDataLength(sID)) == 0)
+ {
+ LoadFlowerPotFromNBT(a_BlockEntities, a_NBT, Child);
+ }
else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0)
{
LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child, a_BlockTypes, a_BlockMetas);
@@ -658,6 +669,12 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
{
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
}
+
+ int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
+ if (EnchTag > 0)
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, a_NBT, FireworksTag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
return true;
}
@@ -760,6 +777,37 @@ void cWSSAnvil::LoadDropperFromNBT(cBlockEntityList & a_BlockEntities, const cPa
+void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
+ int x, y, z;
+ if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
+ {
+ return;
+ }
+ std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(x, y, z, m_World));
+ short ItemType = 0, ItemData = 0;
+
+ int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
+ if (currentLine >= 0)
+ {
+ ItemType = (short) a_NBT.GetInt(currentLine);
+ }
+
+ currentLine = a_NBT.FindChildByName(a_TagIdx, "Data");
+ if (currentLine >= 0)
+ {
+ ItemData = (short) a_NBT.GetInt(currentLine);
+ }
+
+ FlowerPot->SetItem(cItem(ItemType, 1, ItemData));
+ a_BlockEntities.push_back(FlowerPot.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
@@ -1010,6 +1058,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadBoatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "EnderCrystal", a_IDTagLength) == 0)
+ {
+ LoadEnderCrystalFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0)
{
LoadFallingBlockFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1055,6 +1107,18 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
+ {
+ LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "XPOrb", a_IDTagLength) == 0)
+ {
+ LoadExpOrbFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "ItemFrame", a_IDTagLength) == 0)
+ {
+ LoadItemFrameFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
{
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1179,7 +1243,7 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
- else if (strncmp(a_IDTag, "Wither", a_IDTagLength) == 0)
+ else if (strncmp(a_IDTag, "WitherBoss", a_IDTagLength) == 0)
{
LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
@@ -1216,6 +1280,20 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
+void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0));
+ if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ a_Entities.push_back(EnderCrystal.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
@@ -1337,6 +1415,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
+ // Load item:
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{
@@ -1347,11 +1426,27 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{
return;
}
+
+ // Load health:
+ int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
+ if (Health > 0)
+ {
+ Pickup->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
+ }
+
+ // Load age:
+ int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
+ if (Age > 0)
+ {
+ Pickup->SetAge(a_NBT.GetShort(Age));
+ }
+
a_Entities.push_back(Pickup.release());
}
@@ -1359,6 +1454,148 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
+void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Fuse Ticks:
+ int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
+ if (FuseTicks > 0)
+ {
+ TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
+ }
+
+ a_Entities.push_back(TNT.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Health:
+ int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
+ if (Health > 0)
+ {
+ ExpOrb->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
+ }
+
+ // Load Age:
+ int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
+ if (Age > 0)
+ {
+ ExpOrb->SetAge(a_NBT.GetShort(Age));
+ }
+
+ // Load Reward (Value):
+ int Reward = a_NBT.FindChildByName(a_TagIdx, "Value");
+ if (Reward > 0)
+ {
+ ExpOrb->SetReward(a_NBT.GetShort(Reward));
+ }
+
+ a_Entities.push_back(ExpOrb.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ int Direction = a_NBT.FindChildByName(a_TagIdx, "Direction");
+ if (Direction > 0)
+ {
+ Direction = (int)a_NBT.GetByte(Direction);
+ if ((Direction < 0) || (Direction > 5))
+ {
+ a_Hanging.SetDirection(BLOCK_FACE_NORTH);
+ }
+ else
+ {
+ a_Hanging.SetDirection(static_cast<eBlockFace>(Direction));
+ }
+ }
+ else
+ {
+ Direction = a_NBT.FindChildByName(a_TagIdx, "Dir");
+ if (Direction > 0)
+ {
+ switch ((int)a_NBT.GetByte(Direction))
+ {
+ case 0: a_Hanging.SetDirection(BLOCK_FACE_NORTH); break;
+ case 1: a_Hanging.SetDirection(BLOCK_FACE_TOP); break;
+ case 2: a_Hanging.SetDirection(BLOCK_FACE_BOTTOM); break;
+ case 3: a_Hanging.SetDirection(BLOCK_FACE_SOUTH); break;
+ }
+ }
+ }
+
+ 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)
+ );
+ }
+}
+
+
+
+
+
+void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ // Load item:
+ int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
+ if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
+ {
+ return;
+ }
+ cItem Item;
+ if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
+ {
+ return;
+ }
+
+ std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
+ if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ ItemFrame->SetItem(Item);
+
+ LoadHangingFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx);
+
+ // Load Rotation:
+ int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation");
+ if (Rotation > 0)
+ {
+ ItemFrame->SetRotation((Byte)a_NBT.GetByte(Rotation));
+ }
+
+ a_Entities.push_back(ItemFrame.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
@@ -2032,6 +2269,12 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
+ int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
+ if (CurrLine > 0)
+ {
+ Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ }
+
a_Entities.push_back(Monster.release());
}
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 4acf3f2a1..1773ee882 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -20,6 +20,7 @@
class cItemGrid;
class cProjectileEntity;
+class cHangingEntity;
@@ -135,6 +136,7 @@ protected:
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas);
void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
@@ -146,8 +148,13 @@ protected:
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ 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 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/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index 4c0684dd8..bb9d4b9e6 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -12,8 +12,10 @@
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/JukeboxEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
@@ -37,7 +39,7 @@ struct cWSSCompact::sChunkHeader
/// The maximum number of PAK files that are cached
-const int MAX_PAK_FILES = 16;
+const size_t MAX_PAK_FILES = 16;
/// The maximum number of unsaved chunks before the cPAKFile saves them to disk
const int MAX_DIRTY_CHUNKS = 16;
@@ -75,12 +77,14 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
case E_BLOCK_CHEST: SaveInto = "Chests"; break;
case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break;
case E_BLOCK_DROPPER: SaveInto = "Droppers"; break;
+ case E_BLOCK_FLOWER_POT: SaveInto = "FlowerPots"; break;
case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break;
case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break;
case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break;
case E_BLOCK_NOTE_BLOCK: SaveInto = "Notes"; break;
case E_BLOCK_JUKEBOX: SaveInto = "Jukeboxes"; break;
case E_BLOCK_COMMAND_BLOCK: SaveInto = "CommandBlocks"; break;
+ case E_BLOCK_HEAD: SaveInto = "MobHeads"; break;
default:
{
@@ -298,6 +302,21 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
}
} // for itr - AllDispensers[]
+ // Load Flowerpots:
+ Json::Value AllFlowerPots = a_Value.get("FlowerPots", Json::nullValue);
+ for (Json::Value::iterator itr = AllFlowerPots.begin(); itr != AllFlowerPots.end(); ++itr)
+ {
+ std::auto_ptr<cFlowerPotEntity> FlowerPotEntity(new cFlowerPotEntity(0, 0, 0, a_World));
+ if (!FlowerPotEntity->LoadFromJson(*itr))
+ {
+ LOGWARNING("ERROR READING FLOWERPOT FROM JSON!" );
+ }
+ else
+ {
+ a_BlockEntities.push_back(FlowerPotEntity.release());
+ }
+ } // for itr - AllFlowerPots[]
+
// Load furnaces:
Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue);
for (Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr)
@@ -331,7 +350,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load note blocks:
Json::Value AllNotes = a_Value.get("Notes", Json::nullValue);
- for( Json::Value::iterator itr = AllNotes.begin(); itr != AllNotes.end(); ++itr )
+ for (Json::Value::iterator itr = AllNotes.begin(); itr != AllNotes.end(); ++itr)
{
std::auto_ptr<cNoteEntity> NoteEntity(new cNoteEntity(0, 0, 0, a_World));
if (!NoteEntity->LoadFromJson(*itr))
@@ -346,7 +365,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load jukeboxes:
Json::Value AllJukeboxes = a_Value.get("Jukeboxes", Json::nullValue);
- for( Json::Value::iterator itr = AllJukeboxes.begin(); itr != AllJukeboxes.end(); ++itr )
+ for (Json::Value::iterator itr = AllJukeboxes.begin(); itr != AllJukeboxes.end(); ++itr)
{
std::auto_ptr<cJukeboxEntity> JukeboxEntity(new cJukeboxEntity(0, 0, 0, a_World));
if (!JukeboxEntity->LoadFromJson(*itr))
@@ -361,7 +380,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load command blocks:
Json::Value AllCommandBlocks = a_Value.get("CommandBlocks", Json::nullValue);
- for( Json::Value::iterator itr = AllCommandBlocks.begin(); itr != AllCommandBlocks.end(); ++itr )
+ for (Json::Value::iterator itr = AllCommandBlocks.begin(); itr != AllCommandBlocks.end(); ++itr)
{
std::auto_ptr<cCommandBlockEntity> CommandBlockEntity(new cCommandBlockEntity(0, 0, 0, a_World));
if (!CommandBlockEntity->LoadFromJson(*itr))
@@ -373,6 +392,21 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
a_BlockEntities.push_back(CommandBlockEntity.release());
}
} // for itr - AllCommandBlocks[]
+
+ // Load mob heads:
+ Json::Value AllMobHeads = a_Value.get("MobHeads", Json::nullValue);
+ for (Json::Value::iterator itr = AllMobHeads.begin(); itr != AllMobHeads.end(); ++itr)
+ {
+ std::auto_ptr<cMobHeadEntity> MobHeadEntity(new cMobHeadEntity(0, 0, 0, a_World));
+ if (!MobHeadEntity->LoadFromJson(*itr))
+ {
+ LOGWARNING("ERROR READING MOB HEAD FROM JSON!" );
+ }
+ else
+ {
+ a_BlockEntities.push_back(MobHeadEntity.release());
+ }
+ } // for itr - AllMobHeads[]
}
@@ -535,7 +569,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
if( ChunksConverted % 32 == 0 )
{
- LOGINFO("Updating \"%s\" version 1 to version 2: %d %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
+ LOGINFO("Updating \"%s\" version 1 to version 2: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
}
ChunksConverted++;
@@ -573,7 +607,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
if (UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
UncompressedSize, UncompressedData.size(),
Header->m_ChunkX, Header->m_ChunkZ
);
@@ -679,7 +713,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
if( ChunksConverted % 32 == 0 )
{
- LOGINFO("Updating \"%s\" version 2 to version 3: %d %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
+ LOGINFO("Updating \"%s\" version 2 to version 3: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
}
ChunksConverted++;
@@ -717,7 +751,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
if (UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
UncompressedSize, UncompressedData.size(),
Header->m_ChunkX, Header->m_ChunkZ
);
@@ -730,7 +764,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Cannot use cChunk::MakeIndex because it might change again?????????
// For compatibility, use what we know is current
- #define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
unsigned int InChunkOffset = 0;
@@ -833,7 +866,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
if (a_UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
a_UncompressedSize, UncompressedData.size(),
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
);
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 64b8d7f31..4df146ec3 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -12,7 +12,7 @@
#define WSSCOMPACT_H_INCLUDED
#include "WorldStorage.h"
-#include "../Vector3i.h"
+#include "../Vector3.h"
#include "json/json.h"
diff --git a/src/main.cpp b/src/main.cpp
index 2ae8a413b..68eea7f4d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -72,7 +72,6 @@ void NonCtrlHandler(int a_Signal)
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
exit(EXIT_FAILURE);
- break;
}
case SIGINT:
case SIGTERM: