diff options
Diffstat (limited to '')
50 files changed, 1159 insertions, 654 deletions
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index f52d970bf..88d40bfd9 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -4,7 +4,7 @@ #include "ManualBindings.h" #undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" - +#include "polarssl/md5.h" #include "Plugin.h" #include "PluginLua.h" #include "PluginManager.h" @@ -25,7 +25,6 @@ #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" @@ -2001,9 +2000,11 @@ static int tolua_cPlugin_Call(lua_State * tolua_S) static int tolua_md5(lua_State* tolua_S) { - std::string SourceString = tolua_tostring(tolua_S, 1, 0); - std::string CryptedString = md5( SourceString ); - tolua_pushstring( tolua_S, CryptedString.c_str() ); + unsigned char Output[16]; + size_t len = 0; + const unsigned char * SourceString = (const unsigned char *)lua_tolstring(tolua_S, 1, &len); + md5(SourceString, len, Output); + lua_pushlstring(tolua_S, (const char *)Output, ARRAYCOUNT(Output)); return 1; } diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index b084d0915..16314290a 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -8,13 +8,6 @@ -cBlockInfo cBlockInfo::ms_Info[256]; -static bool g_IsBlockInfoInitialized = false; - - - - - cBlockInfo::cBlockInfo() : m_LightValue(0x00) , m_SpreadLightFalloff(0x0f) @@ -42,12 +35,17 @@ cBlockInfo::~cBlockInfo() +/** This accessor makes sure that the cBlockInfo structures are properly initialized exactly once. +It does so by using the C++ singleton approximation - storing the actual singleton as the function's static variable. +It works only if it is called for the first time before the app spawns other threads. */ cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type) { - if (!g_IsBlockInfoInitialized) + static cBlockInfo ms_Info[256]; + static bool IsBlockInfoInitialized = false; + if (!IsBlockInfoInitialized) { - cBlockInfo::Initialize(); - g_IsBlockInfoInitialized = true; + cBlockInfo::Initialize(ms_Info); + IsBlockInfoInitialized = true; } return ms_Info[a_Type]; } @@ -56,399 +54,408 @@ cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type) -void cBlockInfo::Initialize(void) +void cBlockInfo::Initialize(cBlockInfoArray & a_Info) { for (unsigned int i = 0; i < 256; ++i) { - if (ms_Info[i].m_Handler == NULL) + if (a_Info[i].m_Handler == NULL) { - ms_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i); + a_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; + a_Info[E_BLOCK_FIRE ].m_LightValue = 15; + a_Info[E_BLOCK_GLOWSTONE ].m_LightValue = 15; + a_Info[E_BLOCK_JACK_O_LANTERN ].m_LightValue = 15; + a_Info[E_BLOCK_LAVA ].m_LightValue = 15; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_LightValue = 15; + a_Info[E_BLOCK_END_PORTAL ].m_LightValue = 15; + a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_LightValue = 15; + a_Info[E_BLOCK_TORCH ].m_LightValue = 14; + a_Info[E_BLOCK_BURNING_FURNACE ].m_LightValue = 13; + a_Info[E_BLOCK_NETHER_PORTAL ].m_LightValue = 11; + a_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_LightValue = 9; + a_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_LightValue = 9; + a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_LightValue = 7; + a_Info[E_BLOCK_BREWING_STAND ].m_LightValue = 1; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_LightValue = 1; + a_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; + a_Info[E_BLOCK_AIR ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_CAKE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_CHEST ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_COBWEB ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_CROPS ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_FENCE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_FENCE_GATE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_FIRE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_GLASS ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_GLASS_PANE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_GLOWSTONE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_TRIPWIRE ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1; + a_Info[E_BLOCK_WALLSIGN ].m_SpreadLightFalloff = 1; + a_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; + a_Info[E_BLOCK_LAVA ].m_SpreadLightFalloff = 3; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_SpreadLightFalloff = 3; + a_Info[E_BLOCK_STATIONARY_WATER ].m_SpreadLightFalloff = 3; + a_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_ANVIL ].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_CAKE ].m_Transparent = true; - ms_Info[E_BLOCK_CARROTS ].m_Transparent = true; - ms_Info[E_BLOCK_CHEST ].m_Transparent = true; - ms_Info[E_BLOCK_COBBLESTONE_WALL ].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_HEAD ].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_LADDER ].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; + a_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true; + a_Info[E_BLOCK_AIR ].m_Transparent = true; + a_Info[E_BLOCK_ANVIL ].m_Transparent = true; + a_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true; + a_Info[E_BLOCK_CAKE ].m_Transparent = true; + a_Info[E_BLOCK_CARROTS ].m_Transparent = true; + a_Info[E_BLOCK_CHEST ].m_Transparent = true; + a_Info[E_BLOCK_COBBLESTONE_WALL ].m_Transparent = true; + a_Info[E_BLOCK_COBWEB ].m_Transparent = true; + a_Info[E_BLOCK_CROPS ].m_Transparent = true; + a_Info[E_BLOCK_DANDELION ].m_Transparent = true; + a_Info[E_BLOCK_DETECTOR_RAIL ].m_Transparent = true; + a_Info[E_BLOCK_ENDER_CHEST ].m_Transparent = true; + a_Info[E_BLOCK_FENCE ].m_Transparent = true; + a_Info[E_BLOCK_FENCE_GATE ].m_Transparent = true; + a_Info[E_BLOCK_FIRE ].m_Transparent = true; + a_Info[E_BLOCK_FLOWER ].m_Transparent = true; + a_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true; + a_Info[E_BLOCK_GLASS ].m_Transparent = true; + a_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true; + a_Info[E_BLOCK_HEAD ].m_Transparent = true; + a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true; + a_Info[E_BLOCK_ICE ].m_Transparent = true; + a_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true; + a_Info[E_BLOCK_LADDER ].m_Transparent = true; + a_Info[E_BLOCK_LAVA ].m_Transparent = true; + a_Info[E_BLOCK_LEAVES ].m_Transparent = true; + a_Info[E_BLOCK_LEVER ].m_Transparent = true; + a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_Transparent = true; + a_Info[E_BLOCK_MELON_STEM ].m_Transparent = true; + a_Info[E_BLOCK_NETHER_BRICK_FENCE ].m_Transparent = true; + a_Info[E_BLOCK_NEW_LEAVES ].m_Transparent = true; + a_Info[E_BLOCK_POTATOES ].m_Transparent = true; + a_Info[E_BLOCK_POWERED_RAIL ].m_Transparent = true; + a_Info[E_BLOCK_PISTON_EXTENSION ].m_Transparent = true; + a_Info[E_BLOCK_PUMPKIN_STEM ].m_Transparent = true; + a_Info[E_BLOCK_RAIL ].m_Transparent = true; + a_Info[E_BLOCK_RED_MUSHROOM ].m_Transparent = true; + a_Info[E_BLOCK_SIGN_POST ].m_Transparent = true; + a_Info[E_BLOCK_SNOW ].m_Transparent = true; + a_Info[E_BLOCK_STAINED_GLASS ].m_Transparent = true; + a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_Transparent = true; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_Transparent = true; + a_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true; + a_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true; + a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true; + a_Info[E_BLOCK_TRIPWIRE ].m_Transparent = true; + a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true; + a_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true; + a_Info[E_BLOCK_TORCH ].m_Transparent = true; + a_Info[E_BLOCK_VINES ].m_Transparent = true; + a_Info[E_BLOCK_WALLSIGN ].m_Transparent = true; + a_Info[E_BLOCK_WATER ].m_Transparent = true; + a_Info[E_BLOCK_WOODEN_BUTTON ].m_Transparent = true; + a_Info[E_BLOCK_WOODEN_DOOR ].m_Transparent = true; + a_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; + a_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_OneHitDig = true; + a_Info[E_BLOCK_BIG_FLOWER ].m_OneHitDig = true; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_OneHitDig = true; + a_Info[E_BLOCK_CARROTS ].m_OneHitDig = true; + a_Info[E_BLOCK_CROPS ].m_OneHitDig = true; + a_Info[E_BLOCK_DANDELION ].m_OneHitDig = true; + a_Info[E_BLOCK_FIRE ].m_OneHitDig = true; + a_Info[E_BLOCK_FLOWER ].m_OneHitDig = true; + a_Info[E_BLOCK_FLOWER_POT ].m_OneHitDig = true; + a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_OneHitDig = true; + a_Info[E_BLOCK_MELON_STEM ].m_OneHitDig = true; + a_Info[E_BLOCK_POTATOES ].m_OneHitDig = true; + a_Info[E_BLOCK_PUMPKIN_STEM ].m_OneHitDig = true; + a_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_OneHitDig = true; + a_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_OneHitDig = true; + a_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_OneHitDig = true; + a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_OneHitDig = true; + a_Info[E_BLOCK_REDSTONE_WIRE ].m_OneHitDig = true; + a_Info[E_BLOCK_RED_MUSHROOM ].m_OneHitDig = true; + a_Info[E_BLOCK_REEDS ].m_OneHitDig = true; + a_Info[E_BLOCK_SAPLING ].m_OneHitDig = true; + a_Info[E_BLOCK_TNT ].m_OneHitDig = true; + a_Info[E_BLOCK_TALL_GRASS ].m_OneHitDig = true; + a_Info[E_BLOCK_TORCH ].m_OneHitDig = true; + a_Info[E_BLOCK_TRIPWIRE ].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_CAKE ].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_HEAD ].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; + a_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_PistonBreakable = true; + a_Info[E_BLOCK_AIR ].m_PistonBreakable = true; + a_Info[E_BLOCK_BED ].m_PistonBreakable = true; + a_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true; + a_Info[E_BLOCK_CAKE ].m_PistonBreakable = true; + a_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true; + a_Info[E_BLOCK_CROPS ].m_PistonBreakable = true; + a_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true; + a_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true; + a_Info[E_BLOCK_FIRE ].m_PistonBreakable = true; + a_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true; + a_Info[E_BLOCK_HEAD ].m_PistonBreakable = true; + a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true; + a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true; + a_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true; + a_Info[E_BLOCK_JACK_O_LANTERN ].m_PistonBreakable = true; + a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true; + a_Info[E_BLOCK_LADDER ].m_PistonBreakable = true; + a_Info[E_BLOCK_LAVA ].m_PistonBreakable = true; + a_Info[E_BLOCK_LEVER ].m_PistonBreakable = true; + a_Info[E_BLOCK_MELON ].m_PistonBreakable = true; + a_Info[E_BLOCK_MELON_STEM ].m_PistonBreakable = true; + a_Info[E_BLOCK_PUMPKIN ].m_PistonBreakable = true; + a_Info[E_BLOCK_PUMPKIN_STEM ].m_PistonBreakable = true; + a_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_PistonBreakable = true; + a_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_PistonBreakable = true; + a_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_PistonBreakable = true; + a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PistonBreakable = true; + a_Info[E_BLOCK_REDSTONE_WIRE ].m_PistonBreakable = true; + a_Info[E_BLOCK_RED_MUSHROOM ].m_PistonBreakable = true; + a_Info[E_BLOCK_REEDS ].m_PistonBreakable = true; + a_Info[E_BLOCK_SNOW ].m_PistonBreakable = true; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_PistonBreakable = true; + a_Info[E_BLOCK_STATIONARY_WATER ].m_PistonBreakable = true; + a_Info[E_BLOCK_STONE_BUTTON ].m_PistonBreakable = true; + a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_PistonBreakable = true; + a_Info[E_BLOCK_TALL_GRASS ].m_PistonBreakable = true; + a_Info[E_BLOCK_TORCH ].m_PistonBreakable = true; + a_Info[E_BLOCK_TRIPWIRE ].m_PistonBreakable = true; + a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_PistonBreakable = true; + a_Info[E_BLOCK_VINES ].m_PistonBreakable = true; + a_Info[E_BLOCK_WATER ].m_PistonBreakable = true; + a_Info[E_BLOCK_WOODEN_BUTTON ].m_PistonBreakable = true; + a_Info[E_BLOCK_WOODEN_DOOR ].m_PistonBreakable = true; + a_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_COBBLESTONE_WALL ].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; - ms_Info[E_BLOCK_HEAD ].m_IsSnowable = false; + a_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_IsSnowable = false; + a_Info[E_BLOCK_AIR ].m_IsSnowable = false; + a_Info[E_BLOCK_BIG_FLOWER ].m_IsSnowable = false; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSnowable = false; + a_Info[E_BLOCK_CACTUS ].m_IsSnowable = false; + a_Info[E_BLOCK_CHEST ].m_IsSnowable = false; + a_Info[E_BLOCK_CROPS ].m_IsSnowable = false; + a_Info[E_BLOCK_COBBLESTONE_WALL ].m_IsSnowable = false; + a_Info[E_BLOCK_DANDELION ].m_IsSnowable = false; + a_Info[E_BLOCK_FIRE ].m_IsSnowable = false; + a_Info[E_BLOCK_FLOWER ].m_IsSnowable = false; + a_Info[E_BLOCK_GLASS ].m_IsSnowable = false; + a_Info[E_BLOCK_ICE ].m_IsSnowable = false; + a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_IsSnowable = false; + a_Info[E_BLOCK_LAVA ].m_IsSnowable = false; + a_Info[E_BLOCK_LILY_PAD ].m_IsSnowable = false; + a_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_IsSnowable = false; + a_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_IsSnowable = false; + a_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSnowable = false; + a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSnowable = false; + a_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSnowable = false; + a_Info[E_BLOCK_RED_MUSHROOM ].m_IsSnowable = false; + a_Info[E_BLOCK_REEDS ].m_IsSnowable = false; + a_Info[E_BLOCK_SAPLING ].m_IsSnowable = false; + a_Info[E_BLOCK_SIGN_POST ].m_IsSnowable = false; + a_Info[E_BLOCK_SNOW ].m_IsSnowable = false; + a_Info[E_BLOCK_STAINED_GLASS ].m_IsSnowable = false; + a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_IsSnowable = false; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSnowable = false; + a_Info[E_BLOCK_STATIONARY_WATER ].m_IsSnowable = false; + a_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false; + a_Info[E_BLOCK_TNT ].m_IsSnowable = false; + a_Info[E_BLOCK_TORCH ].m_IsSnowable = false; + a_Info[E_BLOCK_TRIPWIRE ].m_IsSnowable = false; + a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false; + a_Info[E_BLOCK_VINES ].m_IsSnowable = false; + a_Info[E_BLOCK_WALLSIGN ].m_IsSnowable = false; + a_Info[E_BLOCK_WATER ].m_IsSnowable = false; + a_Info[E_BLOCK_RAIL ].m_IsSnowable = false; + a_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSnowable = false; + a_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false; + a_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false; + a_Info[E_BLOCK_COBWEB ].m_IsSnowable = false; + a_Info[E_BLOCK_HEAD ].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_WALL ].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; + a_Info[E_BLOCK_BRICK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_COBBLESTONE_WALL ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_DIAMOND_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_EMERALD_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_END_STONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_GOLD_BLOCK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_GOLD_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_IRON_BLOCK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_IRON_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_LAPIS_BLOCK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_LAPIS_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_NETHERRACK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_NETHER_BRICK ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_NETHER_BRICK_STAIRS ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_OBSIDIAN ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_REDSTONE_ORE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_SANDSTONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_SANDSTONE_STAIRS ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_SNOW ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_STONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_STONE_BRICKS ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_STONE_BRICK_STAIRS ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_STONE_SLAB ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_FURNACE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_LIT_FURNACE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_ANVIL ].m_RequiresSpecialTool = true; + a_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_CAKE ].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_FENCE ].m_IsSolid = false; - ms_Info[E_BLOCK_FENCE_GATE ].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; + a_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSolid = false; + a_Info[E_BLOCK_AIR ].m_IsSolid = false; + a_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false; + a_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false; + a_Info[E_BLOCK_CAKE ].m_IsSolid = false; + a_Info[E_BLOCK_CARROTS ].m_IsSolid = false; + a_Info[E_BLOCK_COBWEB ].m_IsSolid = false; + a_Info[E_BLOCK_CROPS ].m_IsSolid = false; + a_Info[E_BLOCK_DANDELION ].m_IsSolid = false; + a_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false; + a_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false; + a_Info[E_BLOCK_FENCE ].m_IsSolid = false; + a_Info[E_BLOCK_FENCE_GATE ].m_IsSolid = false; + a_Info[E_BLOCK_FIRE ].m_IsSolid = false; + a_Info[E_BLOCK_FLOWER ].m_IsSolid = false; + a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false; + a_Info[E_BLOCK_LAVA ].m_IsSolid = false; + a_Info[E_BLOCK_LEVER ].m_IsSolid = false; + a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false; + a_Info[E_BLOCK_MELON_STEM ].m_IsSolid = false; + a_Info[E_BLOCK_NETHER_PORTAL ].m_IsSolid = false; + a_Info[E_BLOCK_PISTON_EXTENSION ].m_IsSolid = false; + a_Info[E_BLOCK_POTATOES ].m_IsSolid = false; + a_Info[E_BLOCK_POWERED_RAIL ].m_IsSolid = false; + a_Info[E_BLOCK_RAIL ].m_IsSolid = false; + a_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSolid = false; + a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSolid = false; + a_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSolid = false; + a_Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false; + a_Info[E_BLOCK_REEDS ].m_IsSolid = false; + a_Info[E_BLOCK_SAPLING ].m_IsSolid = false; + a_Info[E_BLOCK_SIGN_POST ].m_IsSolid = false; + a_Info[E_BLOCK_SNOW ].m_IsSolid = false; + a_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false; + a_Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false; + a_Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false; + a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_IsSolid = false; + a_Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false; + a_Info[E_BLOCK_TORCH ].m_IsSolid = false; + a_Info[E_BLOCK_TRIPWIRE ].m_IsSolid = false; + a_Info[E_BLOCK_VINES ].m_IsSolid = false; + a_Info[E_BLOCK_WALLSIGN ].m_IsSolid = false; + a_Info[E_BLOCK_WATER ].m_IsSolid = false; + a_Info[E_BLOCK_WOODEN_BUTTON ].m_IsSolid = false; + a_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_IsSolid = false; + a_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; + a_Info[E_BLOCK_NEW_LOG ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_BLOCK_OF_COAL ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_BLOCK_OF_REDSTONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_BOOKCASE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_BRICK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_CLAY ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_COAL_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_COBBLESTONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_COMMAND_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_CRAFTING_TABLE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DIAMOND_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DIAMOND_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DIRT ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DISPENSER ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_DROPPER ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_EMERALD_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_EMERALD_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_END_STONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_FURNACE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_GLOWSTONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_GOLD_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_GOLD_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_GRASS ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_GRAVEL ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_HARDENED_CLAY ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_HAY_BALE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_ICE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_IRON_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_IRON_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_JACK_O_LANTERN ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_JUKEBOX ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_LAPIS_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_NETHER_BRICK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_NETHER_QUARTZ_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_NOTE_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_OBSIDIAN ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_PACKED_ICE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_PLANKS ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_PUMPKIN ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_QUARTZ_BLOCK ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_REDSTONE_ORE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_SANDSTONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_SAND ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_SILVERFISH_EGG ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_SPONGE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_STAINED_CLAY ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_WOOL ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_STONE ].m_FullyOccupiesVoxel = true; + a_Info[E_BLOCK_STONE_BRICKS ].m_FullyOccupiesVoxel = true; } diff --git a/src/BlockInfo.h b/src/BlockInfo.h index 40c1db867..d6d4e7430 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -16,18 +16,8 @@ class cBlockHandler; class cBlockInfo { public: - // tolua_end - - cBlockInfo(); - - ~cBlockInfo(); - - /** (Re-)Initializes the internal BlockInfo structures. */ - static void Initialize(void); - // tolua_begin - - /** Returns the associated BlockInfo structure. */ + /** Returns the associated BlockInfo structure for the specified block type. */ static cBlockInfo & Get(BLOCKTYPE a_Type); @@ -79,13 +69,18 @@ public: inline static cBlockHandler * GetHandler (BLOCKTYPE a_Type) { return Get(a_Type).m_Handler; } - protected: + /** Storage for all the BlockInfo structures. */ + typedef cBlockInfo cBlockInfoArray[256]; - // TODO xdot: Change to std::vector to support dynamic block IDs - static cBlockInfo ms_Info[256]; + /** Creates a default BlockInfo structure, initializes all values to their defaults */ + cBlockInfo(); + /** Cleans up the stored values */ + ~cBlockInfo(); + /** Initializes the specified BlockInfo structures with block-specific values. */ + static void Initialize(cBlockInfoArray & a_BlockInfos); }; // tolua_export diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 4b2f6f618..7d9af207d 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -102,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) && (cBlockInfo::IsSolid(BlockIsOn)); + return (a_RelY > 0) && (cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); } } ; diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 405c9bf43..3ddb7531d 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -65,6 +65,8 @@ #include "BlockRedstoneRepeater.h" #include "BlockRedstoneTorch.h" #include "BlockTNT.h" +#include "BlockTripwire.h" +#include "BlockTripwireHook.h" #include "BlockSand.h" #include "BlockSapling.h" #include "BlockSideways.h" @@ -291,6 +293,8 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE 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_TRIPWIRE: return new cBlockTripwireHandler (a_BlockType); + case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType); case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType); case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType); // TODO: This needs a special handler case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType); diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index f1d3ff6d2..afe43abf8 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -22,7 +22,7 @@ public: // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08); - a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER, Meta); // SetMeta doesn't work for unpowering levers, so setblock + a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); } @@ -104,7 +104,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) && cBlockInfo::IsSolid(BlockIsOn); + return (a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn); } diff --git a/src/Blocks/BlockStone.h b/src/Blocks/BlockStone.h index af4c6509a..cd5230f49 100644 --- a/src/Blocks/BlockStone.h +++ b/src/Blocks/BlockStone.h @@ -2,8 +2,6 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" -#include "../World.h" diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 8ddec8de1..44c33c429 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -154,7 +154,11 @@ public: if ( (BlockInQuestion == E_BLOCK_GLASS) || + (BlockInQuestion == E_BLOCK_STAINED_GLASS) || (BlockInQuestion == E_BLOCK_FENCE) || + (BlockInQuestion == E_BLOCK_SOULSAND) || + (BlockInQuestion == E_BLOCK_MOB_SPAWNER) || + (BlockInQuestion == E_BLOCK_END_PORTAL_FRAME) || // Actual vanilla behaviour (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL) ) diff --git a/src/Blocks/BlockTripwire.h b/src/Blocks/BlockTripwire.h new file mode 100644 index 000000000..3ab17bf4a --- /dev/null +++ b/src/Blocks/BlockTripwire.h @@ -0,0 +1,32 @@ + +#pragma once + +#include "BlockHandler.h" + + + + + +class cBlockTripwireHandler : + public cBlockHandler +{ +public: + cBlockTripwireHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0)); + } + + virtual const char * GetStepSound(void) override + { + return ""; + } +}; + + + + diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h new file mode 100644 index 000000000..f849fb8ad --- /dev/null +++ b/src/Blocks/BlockTripwireHook.h @@ -0,0 +1,82 @@ +#pragma once + +#include "BlockHandler.h" +#include "MetaRotator.h" + + + + + +class cBlockTripwireHookHandler : + public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01> +{ +public: + cBlockTripwireHookHandler(BLOCKTYPE a_BlockType) + : cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01>(a_BlockType) + { + } + + 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; + + a_BlockMeta = DirectionToMetadata(a_BlockFace); + + return true; + } + + inline static NIBBLETYPE DirectionToMetadata(eBlockFace a_Direction) + { + switch (a_Direction) + { + case BLOCK_FACE_XM: return 0x1; + case BLOCK_FACE_XP: return 0x3; + case BLOCK_FACE_ZM: return 0x2; + case BLOCK_FACE_ZP: return 0x0; + default: ASSERT(!"Unhandled tripwire hook direction!"); return 0x0; + } + } + + inline static eBlockFace MetadataToDirection(NIBBLETYPE a_Meta) + { + switch (a_Meta & 0x03) + { + case 0x1: return BLOCK_FACE_XM; + case 0x3: return BLOCK_FACE_XP; + case 0x2: return BLOCK_FACE_ZM; + case 0x0: return BLOCK_FACE_ZP; + default: ASSERT(!"Unhandled tripwire hook metadata!"); return BLOCK_FACE_NONE; + } + } + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + // Reset meta to 0 + a_Pickups.push_back(cItem(E_BLOCK_TRIPWIRE_HOOK, 1, 0)); + } + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + NIBBLETYPE Meta; + a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); + + AddFaceDirection(a_RelX, a_RelY, a_RelZ, MetadataToDirection(Meta), true); + BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); + + return (a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn); + } + + virtual const char * GetStepSound(void) override + { + return "step.wood"; + } +}; + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 335ce8315..b1b880b7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required (VERSION 2.8.2) project (MCServer) -include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/") -include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include") -include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include") +include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/") +include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/jsoncpp/include") +include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++) set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs) @@ -119,7 +119,8 @@ if (NOT MSVC) # lib dependencies are not included - + include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") + #add cpp files here add_library(Bindings Bindings/Bindings @@ -134,7 +135,7 @@ if (NOT MSVC) Bindings/WebPlugin ) - target_link_libraries(Bindings lua sqlite tolualib) + target_link_libraries(Bindings lua sqlite tolualib polarssl) #clear file file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependecies.txt) @@ -260,4 +261,4 @@ endif () if (WIN32) target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) endif() -target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp polarssl zlib lua sqlite) +target_link_libraries(${EXECUTABLE} luaexpat iniFile jsoncpp polarssl zlib sqlite lua) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 1320d5ccd..0fee40cac 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2701,7 +2701,7 @@ void cChunk::BroadcastChunkData(cChunkDataSerializer & a_Serializer, const cClie -void cChunk::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude) +void cChunk::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) { @@ -2709,7 +2709,7 @@ void cChunk::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_ { continue; } - (*itr)->SendCollectPickup(a_Pickup, a_Player); + (*itr)->SendCollectEntity(a_Entity, a_Player); } // for itr - LoadedByClient[] } diff --git a/src/Chunk.h b/src/Chunk.h index 7664a7afd..e9d964e05 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -279,7 +279,7 @@ public: void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); void BroadcastChunkData (cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); + void BroadcastCollectEntity (const cEntity & a_Entity, 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); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index d2ccca94e..c9fb0b59e 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -419,16 +419,16 @@ void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali -void cChunkMap::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude) +void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Pickup.GetChunkX(), ZERO_CHUNK_Y, a_Pickup.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; } // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastCollectPickup(a_Pickup, a_Player, a_Exclude); + Chunk->BroadcastCollectEntity(a_Entity, a_Player, a_Exclude); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 3ee0bab3c..433516490 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -70,6 +70,7 @@ public: void BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a_blockY, int a_blockZ, char a_stage, const cClientHandle * a_Exclude = NULL); void BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude); void BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); + void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, 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); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 46083a8f1..6b71f0924 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -30,7 +30,7 @@ #include "CompositeChat.h" #include "Items/ItemSword.h" -#include "md5/md5.h" +#include "polarssl/md5.h" @@ -239,18 +239,16 @@ AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) // xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B // Generate an md5 checksum, and use it as base for the ID: - MD5 Checksum(a_Username); - AString UUID = Checksum.hexdigest(); - UUID[12] = '3'; // Version 3 UUID - UUID[16] = '8'; // Variant 1 UUID - - // Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions: - UUID.insert(8, "-"); - UUID.insert(13, "-"); - UUID.insert(18, "-"); - UUID.insert(23, "-"); - - return UUID; + unsigned char MD5[16]; + md5((const unsigned char *)a_Username.c_str(), a_Username.length(), MD5); + MD5[6] &= 0x0f; // Need to trim to 4 bits only... + MD5[8] &= 0x0f; // ... otherwise %01x overflows into two chars + return Printf("%02x%02x%02x%02x-%02x%02x-3%01x%02x-8%01x%02x-%02x%02x%02x%02x%02x%02x", + MD5[0], MD5[1], MD5[2], MD5[3], + MD5[4], MD5[5], MD5[6], MD5[7], + MD5[8], MD5[9], MD5[10], MD5[11], + MD5[12], MD5[13], MD5[14], MD5[15] + ); } @@ -365,6 +363,9 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID) // Send scoreboard data World->GetScoreBoard().SendTo(*this); + // Send statistics + SendStatistics(m_Player->GetStatManager()); + // Delay the first ping until the client "settles down" // This should fix #889, "BadCast exception, cannot convert bit to fm" error in client cTimer t1; @@ -1085,12 +1086,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo void cClientHandle::FinishDigAnimation() { - if ( - !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet - (m_LastDigBlockX == -1) || - (m_LastDigBlockY == -1) || - (m_LastDigBlockZ == -1) - ) + if (!m_HasStartedDigging) // Hasn't received the DIG_STARTED packet { return; } @@ -2077,9 +2073,9 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ -void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cClientHandle::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { - m_Protocol->SendCollectPickup(a_Pickup, a_Player); + m_Protocol->SendCollectEntity(a_Entity, a_Player); } @@ -2401,9 +2397,9 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec -void cClientHandle::SendRespawn(const cWorld & a_World) +void cClientHandle::SendRespawn(const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks) { - m_Protocol->SendRespawn(a_World); + m_Protocol->SendRespawn(a_World, a_ShouldIgnoreDimensionChecks); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 3e18cbdad..6f2c86b27 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -123,7 +123,7 @@ public: void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = ""); void SendChat (const cCompositeChat & a_Message); void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer); - void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player); + void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player); void SendDestroyEntity (const cEntity & a_Entity); void SendDisconnect (const AString & a_Reason); void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ); @@ -156,7 +156,7 @@ public: void SendPlayerSpawn (const cPlayer & a_Player); void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); - void SendRespawn (const cWorld & a_World); + void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 8d2569125..4727f67a9 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -3,6 +3,7 @@ #include "Player.h" #include "ArrowEntity.h" #include "../Chunk.h" +#include "FastRandom.h" @@ -24,9 +25,9 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a SetYawFromSpeed(); SetPitchFromSpeed(); LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", - m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), - GetYaw(), GetPitch() - ); + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetYaw(), GetPitch() + ); } @@ -44,6 +45,10 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_bIsCollected(false), m_HitBlockPos(0, 0, 0) { + if (a_Player.IsGameModeCreative()) + { + m_PickupState = psInCreative; + } } @@ -109,7 +114,14 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); // Broadcast successful hit sound - m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_World->BroadcastSoundEffect( + "random.successful_hit", + (int)std::floor(GetPosX() * 8.0), + (int)std::floor(GetPosY() * 8.0), + (int)std::floor(GetPosZ() * 8.0), + 0.5f, + 0.75f + ((float)((GetUniqueID() * 23) % 32)) / 64.0f + ); Destroy(); } @@ -120,16 +132,33 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) void cArrowEntity::CollectedBy(cPlayer * a_Dest) { - if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) + if (m_IsInGround && !m_bIsCollected && CanPickup(*a_Dest)) { - int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); - if (NumAdded > 0) // Only play effects if there was space in inventory + // Do not add the arrow to the inventory when the player is in creative: + if (!a_Dest->IsGameModeCreative()) { - m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); - // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) - m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - m_bIsCollected = true; + int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); + if (NumAdded == 0) + { + // No space in the inventory + return; + } } + + // TODO: BroadcastCollectPickup needs a cPickup, which we don't have + // m_World->BroadcastCollectPickup(*this, *a_Dest); + + m_bIsCollected = true; + + cFastRandom Random; + m_World->BroadcastSoundEffect( + "random.pop", + (int)std::floor(GetPosX() * 8.0), + (int)std::floor(GetPosY() * 8), + (int)std::floor(GetPosZ() * 8), + 0.2F, + ((Random.NextFloat(1.0F) - Random.NextFloat(1.0F)) * 0.7F + 1.0F) * 2.0F + ); } } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index ee7ce06ac..2b256e766 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1090,7 +1090,10 @@ void cEntity::HandleAir(void) if (IsSubmerged()) { - SetSpeedY(1); // Float in the water + if (!IsPlayer()) // Players control themselves + { + SetSpeedY(1); // Float in the water + } // Either reduce air level or damage player if (m_AirLevel < 1) diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 0fd006485..10b6bbd5c 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -30,7 +30,7 @@ public: virtual bool Item(cEntity * a_Entity) override { - if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() == m_Pickup->GetUniqueID()) || a_Entity->IsDestroyed()) + if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() <= m_Pickup->GetUniqueID()) || a_Entity->IsDestroyed()) { return false; } @@ -38,10 +38,31 @@ public: Vector3d EntityPos = a_Entity->GetPosition(); double Distance = (EntityPos - m_Position).Length(); - if ((Distance < 1.2) && ((cPickup *)a_Entity)->GetItem().IsEqual(m_Pickup->GetItem())) + cItem & Item = ((cPickup *)a_Entity)->GetItem(); + if ((Distance < 1.2) && Item.IsEqual(m_Pickup->GetItem())) { - m_Pickup->GetItem().AddCount(((cPickup *)a_Entity)->GetItem().m_ItemCount); - a_Entity->Destroy(); + short CombineCount = Item.m_ItemCount; + if ((CombineCount + m_Pickup->GetItem().m_ItemCount) > Item.GetMaxStackSize()) + { + CombineCount = Item.GetMaxStackSize() - m_Pickup->GetItem().m_ItemCount; + } + + if (CombineCount <= 0) + { + return false; + } + + m_Pickup->GetItem().AddCount((char)CombineCount); + Item.m_ItemCount -= CombineCount; + + if (Item.m_ItemCount <= 0) + { + a_Entity->Destroy(); + } + else + { + a_Entity->GetWorld()->BroadcastEntityMetadata(*a_Entity); + } m_FoundMatchingPickup = true; } return false; @@ -129,7 +150,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) } } - if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me + if (!IsDestroyed() && (m_Item.m_ItemCount < m_Item.GetMaxStackSize())) // Don't combine into an already full pickup { cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries @@ -206,7 +227,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) m_World->BroadcastCollectPickup(*this, *a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - if (m_Item.m_ItemCount == 0) + if (m_Item.m_ItemCount <= 0) { // All of the pickup has been collected, schedule the pickup for destroying m_bCollected = true; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index e1e03fded..daf1ef2cc 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1,4 +1,4 @@ - + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Player.h" @@ -412,6 +412,7 @@ void cPlayer::StartChargingBow(void) LOGD("Player \"%s\" started charging their bow", GetName().c_str()); m_IsChargingBow = true; m_BowCharge = 0; + m_World->BroadcastEntityMetadata(*this, m_ClientHandle); } @@ -424,6 +425,8 @@ int cPlayer::FinishChargingBow(void) int res = m_BowCharge; m_IsChargingBow = false; m_BowCharge = 0; + m_World->BroadcastEntityMetadata(*this, m_ClientHandle); + return res; } @@ -436,6 +439,7 @@ void cPlayer::CancelChargingBow(void) LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", GetName().c_str(), m_BowCharge); m_IsChargingBow = false; m_BowCharge = 0; + m_World->BroadcastEntityMetadata(*this, m_ClientHandle); } @@ -972,7 +976,7 @@ void cPlayer::Respawn(void) m_LifetimeTotalXp = 0; // ToDo: send score to client? How? - m_ClientHandle->SendRespawn(*m_World); + m_ClientHandle->SendRespawn(*m_World, true); // Extinguish the fire: StopBurning(); @@ -1909,7 +1913,7 @@ void cPlayer::HandleFood(void) { m_FoodTickTimer = 0; - if (m_FoodLevel >= 17) + if ((m_FoodLevel > 17) && (GetHealth() < GetMaxHealth())) { // Regenerate health from food, incur 3 pts of food exhaustion: Heal(1); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index b2142a18b..2f7957f16 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -404,7 +404,7 @@ public: // cEntity overrides: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } - virtual bool IsRclking (void) const { return IsEating(); } + virtual bool IsRclking (void) const { return IsEating() || IsChargingBow(); } virtual void Detach(void); diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 2cb204ccf..8add9610c 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -5,7 +5,8 @@ #include "Item.h" #include <fstream> -#include <sstream> + +#define FURNACE_RECIPE_FILE "furnace.txt" @@ -54,128 +55,207 @@ void cFurnaceRecipe::ReloadRecipes(void) ClearRecipes(); LOGD("Loading furnace recipes..."); - std::ifstream f; - char a_File[] = "furnace.txt"; - f.open(a_File, std::ios::in); - + std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in); if (!f.good()) { - f.close(); - LOG("Could not open the furnace recipes file \"%s\"", a_File); + LOG("Could not open the furnace recipes file \"%s\". No furnace recipes are available.", FURNACE_RECIPE_FILE); return; } + + unsigned int LineNum = 0; + AString ParsingLine; - // TODO: Replace this messy parse with a high-level-structured one (ReadLine / ProcessLine) - bool bSyntaxError = false; - while (f.good()) + while (std::getline(f, ParsingLine)) { - char c; + LineNum++; + ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove ALL whitespace from the line + if (ParsingLine.empty()) + { + continue; + } - ////////////////////////////////////////////////////////////////////////// - // comments - f >> c; - f.unget(); - if( c == '#' ) + switch (ParsingLine[0]) { - while( f.good() && c != '\n' ) + case '#': { - f.get( c ); + // Comment + break; } - continue; - } + + case '!': + { + AddFuelFromLine(ParsingLine, LineNum); + break; + } + + default: + { + AddRecipeFromLine(ParsingLine, LineNum); + break; + } + } // switch (ParsingLine[0]) + } // while (getline(ParsingLine)) + + LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); +} + + + + + +void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, int a_LineNum) +{ + // Fuel + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) + + if ( + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "=", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "0123456789", a_Line, a_LineNum, IBurnTime, true) // Read item burn time - last value + ) + { + return; + } + + // Add to fuel list: + Fuel F; + F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + F.BurnTime = IBurnTime; + m_pState->Fuel.push_back(F); +} + + + + + +void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, int a_LineNum) +{ + int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; + int OItemID = 0, OItemCount = 0, OItemHealth = 0; + AString::size_type BeginPos = 0; // Begin at start of line + + if ( + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID + !ReadOptionalNumbers(BeginPos, ":", "@", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health) + !ReadMandatoryNumber(BeginPos, "=", a_Line, a_LineNum, IBurnTime) || // Read item burn time + !ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, OItemID) || // Read result ID + !ReadOptionalNumbers(BeginPos, ":", "012456789", a_Line, a_LineNum, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value + ) + { + return; + } + + // Add to recipe list + Recipe R; + R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); + R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth); + R.CookTime = IBurnTime; + m_pState->Recipes.push_back(R); +} + + + - ////////////////////////////////////////////////////////////////////////// - // Line breaks - f.get( c ); - while( f.good() && ( c == '\n' || c == '\r' ) ) { f.get( c ); } - if (f.eof()) +void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing) +{ + LOGWARN("Error parsing furnace recipes at line %i pos " SIZE_T_FMT ": missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str()); +} + + + + + +bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue) +{ + // TODO: replace atoi with std::stoi + AString::size_type End; + if (a_IsLastValue) + { + End = a_Text.find_first_not_of(a_Delimiter, a_Begin); + } + else + { + End = a_Text.find_first_of(a_Delimiter, a_Begin); + if (End == AString::npos) { - break; + PrintParseError(a_Line, a_Begin, a_Delimiter); + return false; } - f.unget(); + } + + // stoi won't throw an exception if the string is alphanumeric, we should check for this + if (!DoesStringContainOnlyNumbers(a_Text.substr(a_Begin, End - a_Begin))) + { + PrintParseError(a_Line, a_Begin, "number"); + return false; + } + a_Value = atoi(a_Text.substr(a_Begin, End - a_Begin).c_str()); + + a_Begin = End + 1; // Jump over delimiter + return true; +} + + + + - ////////////////////////////////////////////////////////////////////////// - // Check for fuel - f >> c; - if( c == '!' ) // It's fuel :) +bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue) +{ + // TODO: replace atoi with std::stoi + AString::size_type End, Begin = a_Begin; + + End = a_Text.find_first_of(a_DelimiterOne, Begin); + if (End != AString::npos) + { + if (DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) { - // Read item - int IItemID = 0, IItemCount = 0, IItemHealth = 0; - f >> IItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> IItemCount; - - // Optional health - f >> c; - if( c != ':' ) - f.unget(); + a_ValueOne = std::atoi(a_Text.substr(Begin, End - Begin).c_str()); + Begin = End + 1; + + if (a_IsLastValue) + { + End = a_Text.find_first_not_of(a_DelimiterTwo, Begin); + } else { - f >> IItemHealth; + End = a_Text.find_first_of(a_DelimiterTwo, Begin); + if (End == AString::npos) + { + PrintParseError(a_Line, Begin, a_DelimiterTwo); + return false; + } } - // Burn time - int BurnTime; - f >> c; if( c != '=' ) { bSyntaxError = true; break; } - f >> BurnTime; + // stoi won't throw an exception if the string is alphanumeric, we should check for this + if (!DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin))) + { + PrintParseError(a_Line, Begin, "number"); + return false; + } + a_ValueTwo = atoi(a_Text.substr(Begin, End - Begin).c_str()); - // Add to fuel list - Fuel F; - F.In = new cItem( (ENUM_ITEM_ID) IItemID, (char)IItemCount, (short)IItemHealth ); - F.BurnTime = BurnTime; - m_pState->Fuel.push_back( F ); - continue; + a_Begin = End + 1; // Jump over delimiter + return true; } - f.unget(); - - ////////////////////////////////////////////////////////////////////////// - // Read items - int IItemID = 0, IItemCount = 0, IItemHealth = 0; - f >> IItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> IItemCount; - - // Optional health - f >> c; - if( c != ':' ) - f.unget(); else { - f >> IItemHealth; + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue); } + } + + return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue); +} - int CookTime; - f >> c; if( c != '@' ) { bSyntaxError = true; break; } - f >> CookTime; - int OItemID = 0, OItemCount = 0, OItemHealth = 0; - f >> c; if( c != '=' ) { bSyntaxError = true; break; } - f >> OItemID; - f >> c; if( c != ':' ) { bSyntaxError = true; break; } - f >> OItemCount; - // Optional health - f >> c; - if( c != ':' ) - f.unget(); - else - { - f >> OItemHealth; - } - // Add to recipe list - Recipe R; - R.In = new cItem( (ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth ); - R.Out = new cItem( (ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth ); - R.CookTime = CookTime; - m_pState->Recipes.push_back( R ); - } - if (bSyntaxError) - { - LOGERROR("ERROR: FurnaceRecipe, syntax error" ); - } - LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); + +bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String) +{ + // TODO: replace this with std::all_of(a_String.begin(), a_String.end(), isdigit) + return (a_String.find_first_not_of("0123456789") == AString::npos); } diff --git a/src/FurnaceRecipe.h b/src/FurnaceRecipe.h index 2f91e9bcb..77ed35a57 100644 --- a/src/FurnaceRecipe.h +++ b/src/FurnaceRecipe.h @@ -41,6 +41,36 @@ public: private: void ClearRecipes(void); + /** Parses the fuel contained in the line, adds it to m_pState's fuels. + Logs a warning to the console on input error. */ + void AddFuelFromLine(const AString & a_Line, int a_LineNum); + + /** Parses the recipe contained in the line, adds it to m_pState's recipes. + Logs a warning to the console on input error. */ + void AddRecipeFromLine(const AString & a_Line, int a_LineNum); + + /** Calls LOGWARN with the line, position, and error */ + static void PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing); + + /** Reads a number from a string given, starting at a given position and ending at a delimiter given + Updates beginning position to the delimiter found + 1, and updates the value to the one read + If it encounters a substring that is not fully numeric, it will call SetParseError() and return false; the caller should abort processing + Otherwise, the function will return true + */ + static bool ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue = false); + + /** Reads two numbers from a string given, starting at a given position and ending at the first delimiter given, then again (with an updated position) until the second delimiter given + Updates beginning position to the second delimiter found + 1, and updates the values to the ones read + If it encounters a substring that is not fully numeric whilst reading the second value, it will call SetParseError() and return false; the caller should abort processing + If this happens whilst reading the first value, it will call ReadMandatoryNumber() with the appropriate position, as this may legitimately occur with the optional value and AString::find_first_of finding the incorrect delimiter. It will return the result of ReadMandatoryNumber() + True will be returned definitively for an optional value that is valid + */ + static bool ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue = false); + + /** Uses std::all_of to determine if a string contains only digits */ + static bool DoesStringContainOnlyNumbers(const AString & a_String); + + struct sFurnaceRecipeState; sFurnaceRecipeState * m_pState; }; diff --git a/src/Globals.h b/src/Globals.h index c5768facf..0c11429bd 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -71,9 +71,24 @@ #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" + #if defined(_WIN32) + // We're compiling on MinGW, which uses an old MSVCRT library that has no support for size_t printfing. + // We need direct size formats: + #if defined(_WIN64) + #define SIZE_T_FMT "%I64u" + #define SIZE_T_FMT_PRECISION(x) "%" #x "I64u" + #define SIZE_T_FMT_HEX "%I64x" + #else + #define SIZE_T_FMT "%u" + #define SIZE_T_FMT_PRECISION(x) "%" #x "u" + #define SIZE_T_FMT_HEX "%x" + #endif + #else + // We're compiling on Linux, so we can use libc's size_t printf format: + #define SIZE_T_FMT "%zu" + #define SIZE_T_FMT_PRECISION(x) "%" #x "zu" + #define SIZE_T_FMT_HEX "%zx" + #endif #define NORETURN __attribute((__noreturn__)) diff --git a/src/Item.cpp b/src/Item.cpp index d6e8b224a..56ceae0b7 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" diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 821e2ab26..940338d0f 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -46,20 +46,17 @@ public: { // Actual shot - produce the arrow with speed based on the ticks that the bow was charged ASSERT(a_Player != NULL); - + int BowCharge = a_Player->FinishChargingBow(); - double Force = (double)BowCharge / 20; - Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client + double Force = (double)BowCharge / 20.0; + Force = (Force * Force + 2.0 * Force) / 3.0; // This formula is used by the 1.6.2 client if (Force < 0.1) { // Too little force, ignore the shot return; } - if (Force > 1) - { - Force = 1; - } - + Force = std::max(Force, 1.0); + // Create the arrow entity: cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); if (Arrow == NULL) @@ -72,8 +69,16 @@ public: Arrow = NULL; return; } - a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow); - a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)Force); + + cFastRandom Random; + a_Player->GetWorld()->BroadcastSoundEffect( + "random.bow", + (int)std::floor(a_Player->GetPosX() * 8.0), + (int)std::floor(a_Player->GetPosY() * 8.0), + (int)std::floor(a_Player->GetPosZ() * 8.0), + 1.0F, + 1.0F / (Random.NextFloat(1.0F) * 0.4F + 1.2F) + (float)Force * 0.5F + ); if (!a_Player->IsGameModeCreative()) { diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index f639423ae..a2fd4e3f8 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -44,6 +44,7 @@ #include "ItemSign.h" #include "ItemMobHead.h" #include "ItemSpawnEgg.h" +#include "ItemString.h" #include "ItemSugarcane.h" #include "ItemSword.h" @@ -129,6 +130,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType); case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); + case E_ITEM_STRING: return new cItemStringHandler(a_ItemType); case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType); case E_ITEM_WOODEN_HOE: diff --git a/src/Items/ItemString.h b/src/Items/ItemString.h new file mode 100644 index 000000000..a97fbe0ce --- /dev/null +++ b/src/Items/ItemString.h @@ -0,0 +1,39 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemStringHandler : + public cItemHandler +{ +public: + cItemStringHandler(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_TRIPWIRE; + a_BlockMeta = 0; + return true; + } +}; + + + + diff --git a/src/Mobs/Pig.cpp b/src/Mobs/Pig.cpp index e862f5aaa..1f77cf613 100644 --- a/src/Mobs/Pig.cpp +++ b/src/Mobs/Pig.cpp @@ -78,3 +78,23 @@ void cPig::OnRightClicked(cPlayer & a_Player) + + +void cPig::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + // If the attachee player is holding a carrot-on-stick, let them drive this pig: + if (m_bIsSaddled && (m_Attachee != NULL)) + { + if (m_Attachee->IsPlayer() && (m_Attachee->GetEquippedWeapon().m_ItemType == E_ITEM_CARROT_ON_STICK)) + { + MoveToPosition((m_Attachee->GetPosition()) + (m_Attachee->GetLookVector()*10)); + m_bMovingToDestination = true; + } + } +} + + + + diff --git a/src/Mobs/Pig.h b/src/Mobs/Pig.h index d434324c1..313af2f44 100644 --- a/src/Mobs/Pig.h +++ b/src/Mobs/Pig.h @@ -19,6 +19,7 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void OnRightClicked(cPlayer & a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_CARROT); } diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 8c24fa541..addf8f928 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -7,6 +7,9 @@ #include "File.h" #include <fstream> +#ifdef _WIN32 + #include <share.h> // for _SH_DENYWRITE +#endif // _WIN32 diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index c6e569919..ac872a2f2 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -64,7 +64,7 @@ public: virtual void SendChat (const AString & a_Message) = 0; virtual void SendChat (const cCompositeChat & a_Message) = 0; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; - virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0; + virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) = 0; virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; virtual void SendDisconnect (const AString & a_Reason) = 0; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; ///< Request the client to open up the sign editor for the sign (1.6+) @@ -100,7 +100,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; - virtual void SendRespawn (const cWorld & a_World) = 0; + virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 491058919..6dc2e918d 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -274,11 +274,11 @@ void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize -void cProtocol125::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cProtocol125::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { cCSLock Lock(m_CSPacket); WriteByte(PACKET_COLLECT_PICKUP); - WriteInt (a_Pickup.GetUniqueID()); + WriteInt (a_Entity.GetUniqueID()); WriteInt (a_Player.GetUniqueID()); Flush(); } @@ -833,12 +833,12 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol125::SendRespawn(const cWorld & a_World) +void cProtocol125::SendRespawn(const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks) { cCSLock Lock(m_CSPacket); - if (m_LastSentDimension == a_World.GetDimension()) + if ((m_LastSentDimension == a_World.GetDimension()) && !a_ShouldIgnoreDimensionChecks) { - // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do + // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) return; } cPlayer * Player = m_Client->GetPlayer(); diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 85418f71f..9dbefd3a3 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -36,7 +36,7 @@ public: virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDisconnect (const AString & a_Reason) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) @@ -72,7 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) 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; diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 1e3fc8de8..31cf99f53 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -188,19 +188,19 @@ void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize -void cProtocol132::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cProtocol132::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { cCSLock Lock(m_CSPacket); WriteByte(PACKET_COLLECT_PICKUP); - WriteInt (a_Pickup.GetUniqueID()); + WriteInt (a_Entity.GetUniqueID()); WriteInt (a_Player.GetUniqueID()); Flush(); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) SendSoundEffect( "random.pop", - (int)(a_Pickup.GetPosX() * 8), (int)(a_Pickup.GetPosY() * 8), (int)(a_Pickup.GetPosZ() * 8), - 0.5, (float)(0.75 + ((float)((a_Pickup.GetUniqueID() * 23) % 32)) / 64) + (int)(a_Entity.GetPosX() * 8), (int)(a_Entity.GetPosY() * 8), (int)(a_Entity.GetPosZ() * 8), + 0.5, (float)(0.75 + ((float)((a_Entity.GetUniqueID() * 23) % 32)) / 64) ); } diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h index 32bc7d581..e5d3ee80c 100644 --- a/src/Protocol/Protocol132.h +++ b/src/Protocol/Protocol132.h @@ -48,7 +48,7 @@ public: virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index 9e0f3f852..eba795f61 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -158,10 +158,10 @@ void cProtocol161::SendPlayerMaxSpeed(void) -void cProtocol161::SendRespawn(const cWorld & a_World) +void cProtocol161::SendRespawn(const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks) { // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast - super::SendRespawn(a_World); + super::SendRespawn(a_World, a_ShouldIgnoreDimensionChecks); SendPlayerMaxSpeed(); } diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index e91dc8a1c..e6e79027e 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -42,7 +42,7 @@ protected: virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; virtual void SendPlayerMaxSpeed(void) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) override; virtual void SendWindowOpen (const cWindow & a_Window) override; virtual int ParseEntityAction (void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 02c577dc8..df9c6b50d 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -351,12 +351,12 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize -void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cProtocol172::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0d); // Collect Item packet - Pkt.WriteInt(a_Pickup.GetUniqueID()); + Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Player.GetUniqueID()); } @@ -986,11 +986,11 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol172::SendRespawn(const cWorld & a_World) +void cProtocol172::SendRespawn(const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks) { - if (m_LastSentDimension == a_World.GetDimension()) + if ((m_LastSentDimension == a_World.GetDimension()) && !a_ShouldIgnoreDimensionChecks) { - // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do + // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) return; } @@ -1221,10 +1221,9 @@ void cProtocol172::SendStatistics(const cStatManager & a_Manager) cPacketizer Pkt(*this, 0x37); Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only - for (unsigned int i = 0; i < (unsigned int)statCount; ++i) + for (size_t i = 0; i < (size_t)statCount; ++i) { StatValue Value = a_Manager.GetValue((eStatistic) i); - const AString & StatName = cStatInfo::GetName((eStatistic) i); Pkt.WriteString(StatName); diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 8be1d9211..1a65cfa1c 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -68,7 +68,7 @@ public: virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDisconnect (const AString & a_Reason) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) @@ -104,7 +104,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) override; 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 virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 80f5da25a..c0c9e08ee 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -181,10 +181,10 @@ void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSe -void cProtocolRecognizer::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { ASSERT(m_Protocol != NULL); - m_Protocol->SendCollectPickup(a_Pickup, a_Player); + m_Protocol->SendCollectEntity(a_Entity, a_Player); } @@ -556,10 +556,10 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a -void cProtocolRecognizer::SendRespawn(const cWorld & a_World) +void cProtocolRecognizer::SendRespawn(const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks) { ASSERT(m_Protocol != NULL); - m_Protocol->SendRespawn(a_World); + m_Protocol->SendRespawn(a_World, a_ShouldIgnoreDimensionChecks); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 5e178447c..0a9a42e93 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -71,7 +71,7 @@ public: virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; + virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDisconnect (const AString & a_Reason) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) @@ -107,7 +107,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendRespawn (const cWorld & a_World) override; + virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) 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; diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index e95af3a1c..4ffda2365 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -217,14 +217,20 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i { ASSERT(a_NewMeta <= 8); // Invalid meta values ASSERT(a_NewMeta > 0); // Source blocks aren't spread - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta)) + + a_NearChunk = a_NearChunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((a_NearChunk == NULL) || (!a_NearChunk->IsValid())) { // Chunk not available return; } + + const int BlockX = a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX; + const int BlockZ = a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ; + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + a_NearChunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta); if (IsAllowedBlock(BlockType)) { @@ -246,15 +252,9 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str() ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - int BaseX = a_NearChunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_NearChunk->GetPosZ() * cChunkDef::Width; - - BaseX += a_RelX; - BaseZ += a_RelZ; - - a_NearChunk->BroadcastSoundEffect("random.fizz", BaseX * 8, a_RelY * 8, BaseZ * 8, 0.5f, 1.5f); + a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f); return; } } @@ -267,15 +267,9 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i FLOG(" Water flowing into lava, turning lava at rel {%d, %d, %d} into %s", a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str() ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - - int BaseX = a_NearChunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_NearChunk->GetPosZ() * cChunkDef::Width; - - BaseX += a_RelX; - BaseZ += a_RelZ; + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - a_NearChunk->BroadcastSoundEffect("random.fizz", BaseX * 8, a_RelY * 8, BaseZ * 8, 0.5f, 1.5f); + a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f); return; } } @@ -303,21 +297,17 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i m_World, PluginInterface, NULL, - a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX, + BlockX, a_RelY, - a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ + BlockZ ); } } // if (CanWashAway) - + // Spread: - FLOG(" Spreading to {%d, %d, %d} with meta %d", - a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX, - a_RelY, - a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ, - a_NewMeta - ); - a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + FLOG(" Spreading to {%d, %d, %d} with meta %d", BlockX, a_RelY, BlockZ, a_NewMeta); + a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + m_World.GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, a_NearChunk); HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); } @@ -409,13 +399,13 @@ bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY if (a_Meta == 0) { // Source lava block - a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0); + a_Chunk->SetBlock(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); + a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0); return true; } } diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 10446a879..866a5b65a 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "IncrementalRedstoneSimulator.h" +#include "BoundingBox.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/CommandBlockEntity.h" @@ -12,10 +13,13 @@ #include "../Blocks/BlockButton.h" #include "../Blocks/BlockLever.h" #include "../Blocks/BlockPiston.h" +#include "../Blocks/BlockTripwireHook.h" + +#define WAKE_SIMULATOR_IF_DIRTY(a_Chunk, a_BlockX, a_BlockY, a_BlockZ) if (a_Chunk->IsRedstoneDirty()) WakeUp(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); + - cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World) : super(a_World), @@ -99,10 +103,11 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, // Changeable sources ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || - ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) || + ((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) || (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) || - (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) + (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) || + ((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0)) ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); @@ -289,6 +294,9 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int switch (dataitr->Data) { case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRIPWIRE: HandleTripwire(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRIPWIRE_HOOK: HandleTripwireHook(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: @@ -1120,7 +1128,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R case E_BLOCK_STONE_PRESSURE_PLATE: { // MCS feature - stone pressure plates can only be triggered by players :D - cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.7f, false); + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.5f, false); if (a_Player != NULL) { @@ -1131,7 +1139,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R else { m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); } break; } @@ -1155,7 +1163,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_NumberOfEntities++; } @@ -1177,7 +1185,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R }; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); unsigned char Power; NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -1198,7 +1206,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); } break; @@ -1223,7 +1231,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_NumberOfEntities++; } @@ -1232,7 +1240,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R bool GetPowerLevel(unsigned char & a_PowerLevel) const { - a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); + a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / 10.f), MAX_POWER_LEVEL); return (a_PowerLevel > 0); } @@ -1245,7 +1253,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R }; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); unsigned char Power; NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); @@ -1266,7 +1274,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); } break; @@ -1291,7 +1299,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); double Distance = (EntityPos - BlockPos).Length(); - if (Distance <= 0.7) + if (Distance <= 0.5) { m_FoundEntity = true; return true; // Break out, we only need to know for plates that at least one entity is on top @@ -1313,7 +1321,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R } ; cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), PressurePlateCallback); NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (PressurePlateCallback.FoundEntity()) @@ -1333,7 +1341,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); } m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); } break; } @@ -1349,6 +1357,131 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R +void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +{ + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; + int RelX = a_RelBlockX, RelZ = a_RelBlockZ; + bool FoundActivated = false; + eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); + + for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks + { + BLOCKTYPE Type; + NIBBLETYPE Meta; + + AddFaceDirection(RelX, a_RelBlockY, RelZ, FaceToGoTowards); + m_Chunk->UnboundedRelGetBlock(RelX, a_RelBlockY, RelZ, Type, Meta); + + if (Type == E_BLOCK_TRIPWIRE) + { + if (Meta == 0x1) + { + FoundActivated = true; + } + } + else if (Type == E_BLOCK_TRIPWIRE_HOOK) + { + if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards) + { + // Other hook not facing in opposite direction + break; + } + else + { + // Tripwire hook not connected at all, AND away all the power state bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); + return; + } + } + else + { + // Tripwire hook not connected at all, AND away all the power state bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); + return; + } + } + + if (FoundActivated) + { + // Connected and activated, set the 3rd and 4th highest bits + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0xC); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + } + else + { + // Connected but not activated, AND away the highest bit + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4); + WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); + } +} + + + + + +void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) +{ + int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX; + int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ; + + class cTripwireCallback : + public cEntityCallback + { + public: + cTripwireCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_FoundEntity(false), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + cBoundingBox bbWire(m_X, m_X + 1, m_Y, m_Y + 0.1, m_Z, m_Z + 1); + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + if (bbEntity.DoesIntersect(bbWire)) + { + m_FoundEntity = true; + return true; // One entity is sufficient to trigger the wire + } + return false; + } + + bool FoundEntity(void) const + { + return m_FoundEntity; + } + + protected: + bool m_FoundEntity; + + int m_X; + int m_Y; + int m_Z; + }; + + cTripwireCallback TripwireCallback(BlockX, a_RelBlockY, BlockZ); + m_World.ForEachEntityInChunk(m_Chunk->GetPosX(), m_Chunk->GetPosZ(), TripwireCallback); + + if (TripwireCallback.FoundEntity()) + { + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); + } + else + { + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); + } +} + + + + + bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 9c1f9460c..6cefdebf2 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -102,6 +102,11 @@ private: void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles pressure plates */ void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); + /** Handles tripwire hooks + Performs correct meta and power setting for self by going in the direction it faces and looking for a continous line of tripwire bounded by another oppositely facing hook + If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task + */ + void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ==================== */ /* ====== CARRIERS ====== */ @@ -134,6 +139,8 @@ private: void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles noteblocks */ void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); + /** Handles tripwires */ + void HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ===================== */ /* ====== Helper functions ====== */ @@ -271,6 +278,7 @@ private: case E_BLOCK_TNT: case E_BLOCK_TRAPDOOR: case E_BLOCK_TRIPWIRE_HOOK: + case E_BLOCK_TRIPWIRE: case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_WOODEN_DOOR: case E_BLOCK_WOODEN_PRESSURE_PLATE: diff --git a/src/World.cpp b/src/World.cpp index 5b067b386..bd7694e96 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1877,9 +1877,18 @@ void cWorld::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer +void cWorld::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) +{ + m_ChunkMap->BroadcastCollectEntity(a_Entity, a_Player, a_Exclude); +} + + + + + void cWorld::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude) { - m_ChunkMap->BroadcastCollectPickup(a_Pickup, a_Player, a_Exclude); + m_ChunkMap->BroadcastCollectEntity(a_Pickup, a_Player, a_Exclude); } diff --git a/src/World.h b/src/World.h index 2b7f78760..692d5a497 100644 --- a/src/World.h +++ b/src/World.h @@ -206,6 +206,7 @@ public: // tolua_end void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); + void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, 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); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 8294d4a00..f35b38859 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -345,6 +345,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C m_Writer.AddDouble("", a_Entity->GetYaw()); m_Writer.AddDouble("", a_Entity->GetPitch()); m_Writer.EndList(); + m_Writer.AddShort("Health", a_Entity->GetHealth()); } @@ -575,7 +576,6 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup) m_Writer.BeginCompound(""); AddBasicEntity(a_Pickup, "Item"); AddItem(a_Pickup->GetItem(), -1, "Item"); - m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth()); m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge()); m_Writer.EndCompound(); } @@ -678,7 +678,6 @@ 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(); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 0f84a0eb1..9870c144a 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -1461,13 +1461,6 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a { 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"); @@ -1513,13 +1506,6 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a 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) @@ -2437,6 +2423,13 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N } a_Entity.SetYaw(Rotation[0]); a_Entity.SetRoll(Rotation[1]); + + // Load health: + int Health = a_NBT.FindChildByName(a_TagIdx, "Health"); + if (Health > 0) + { + a_Entity.SetHealth(a_NBT.GetShort(Health)); + } return true; } |