diff options
131 files changed, 2756 insertions, 1841 deletions
diff --git a/COMPILING.md b/COMPILING.md index 139f1a0ee..ea6b580d5 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -45,7 +45,30 @@ It is possible to use an external profiler to learn more about how the code perf There's a script file, `MCServer/profile_run.cmd` that encapsulates most of the profiling work, have a look at the comments at the top of that script for details on how to get it to work. You'll need to change to a profiled configuration (both debug and release can be profiled). -## Linux, MacOS, FreeBSD etc. ## +## OSX ## +Install git from its [website](http://git-scm.com) or homebrew: `brew install git`. + +Install Xcode (commandline tools are recommended) from the App Store or https://developer.apple.com/downloads. + +Install CMake from its [website](http://cmake.org) or homebrew: `brew install cmake`. + +### Getting the sources ### +``` +mkdir MCServer +cd MCServer +git clone https://github.com/mc-server/MCServer.git . +git submodule init +git submodule update +``` + +### Building ### + +Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms), using Xcode as cmake's generator. If no generator is specified, CMake will use the Makefile generator, in which case you must build with the `make` command. + +After doing so, run the command `xcodebuild lib/polarssl/POLARSSL.xcodeproj` in the build directory, in order to build polarssl, a library that is required by MCServer. Lastly, run the command `xcodebuild` to build MCServer. Optionally, you may open the project files for polarssl and then MCServer in Xcode and build there. + + +## Linux, FreeBSD etc. ## Install git, cmake and gcc or clang, using your platform's package manager: ``` @@ -61,6 +84,14 @@ git submodule init git submodule update ``` +### Building ### + +Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms). + +After doing so, run the command `make` in the build directory, and MCServer will build. + +## CMake on Unix-based platforms ### + ### Release Mode ### Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better. @@ -69,8 +100,10 @@ Assuming you are in the MCServer folder created in the initial setup step, you n ``` mkdir Release cd Release -cmake -DCMAKE_BUILD_TYPE=RELEASE .. && make +cmake -DCMAKE_BUILD_TYPE=RELEASE .. ``` +NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive. + The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer`. ### Debug Mode ### @@ -81,8 +114,10 @@ Assuming you are in the MCServer folder created in the Getting the sources step, ``` mkdir Debug cd Debug -cmake -DCMAKE_BUILD_TYPE=DEBUG .. && make +cmake -DCMAKE_BUILD_TYPE=DEBUG .. ``` +NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive. + The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer_debug`. ### 32 Bit Mode switch ### diff --git a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua index a3301a8c6..204cb63d2 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnDisconnect.lua @@ -2,23 +2,33 @@ return { HOOK_DISCONNECT = { - CalledWhen = "A player has explicitly disconnected.", + CalledWhen = [[ + A client has disconnected, either by explicitly sending the disconnect packet (in older protocols) or + their connection was terminated + ]], DefaultFnName = "OnDisconnect", -- also used as pagename Desc = [[ - This hook is called when a client is about to be disconnected from the server, for whatever reason. - - <p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for - the client sending the server a disconnect packet, which no longer happens.</b></p> + This hook is called when a client has disconnected from the server, for whatever reason. It is also + called when the client sends the Disconnect packet (only in pre-1.7 protocols). This hook is not called + for server ping connections.</p> + <p> + Note that the hook is called even for connections to players who failed to auth. In such a case there's + no {{cPlayer}} object associated with the client.</p> + <p> + See also the {{OnHandshake|HOOK_HANDSHAKE}} hook which is called when the client connects (and presents + a handshake message, so that they are not just status-pinging). If you need to store a per-player + object, use the {{OnPlayerJoined|HOOK_PLAYER_JOINED}} and {{OnPlayerDestroyed|HOOK_PLAYER_DESTROYED}} + hooks instead, those are guaranteed to have the {{cPlayer}} object associated. ]], Params = { - { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" }, + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client who has disconnected" }, { Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" }, }, Returns = [[ If the function returns false or no value, MCServer calls other plugins' callbacks for this event. If the function returns true, no other plugins are called for this event. In either case, - the player is disconnected. + the client is disconnected. ]], }, -- HOOK_DISCONNECT } diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index 52199740b..a25bab9cf 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -27,10 +27,14 @@ local function LoadAPIFiles(a_Folder, a_DstTable) -- We only want .lua files from the folder: if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then local TablesFn, Err = loadfile(FileName); - if (TablesFn == nil) then + if (type(TablesFn) ~= "function") then LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'."); else local Tables = TablesFn(); + if (type(Tables) ~= "table") then + LOGWARNING("Cannot load API descriptions from " .. FileName .. ", returned object is not a table (" .. type(Tables) .. ")."); + break + end for k, cls in pairs(Tables) do a_DstTable[k] = cls; end diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be5 +Subproject 5c8557d4fdfa580c100510cde07a1a778ea2e24 diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h index 54e7e9251..a9b5aa1b1 100644 --- a/Tools/ProtoProxy/Globals.h +++ b/Tools/ProtoProxy/Globals.h @@ -221,7 +221,7 @@ typedef unsigned char Byte; #if (defined(_MSC_VER) && (_MSC_VER < 1600)) // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier #define SharedPtr std::tr1::shared_ptr -#elif (__cplusplus >= 201103L) +#elif (defined(_MSC_VER) || (__cplusplus >= 201103L)) // C++11 has std::shared_ptr in <memory>, included earlier #define SharedPtr std::shared_ptr #else diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index 19db9723a..ea03f5d35 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -243,7 +243,7 @@ int cIniFile::FindKey(const AString & a_KeyName) const { if (CheckCase(names[keyID]) == CaseKeyName) { - return keyID; + return (int)keyID; } } return noID; @@ -279,7 +279,7 @@ int cIniFile::AddKeyName(const AString & keyname) { names.resize(names.size() + 1, keyname); keys.resize(keys.size() + 1); - return names.size() - 1; + return (int)names.size() - 1; } @@ -683,7 +683,7 @@ int cIniFile::GetNumKeyComments(const int keyID) const { if (keyID < (int)keys.size()) { - return keys[keyID].comments.size(); + return (int)keys[keyID].comments.size(); } return 0; } diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index db865cfa4..985a18a95 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -42,7 +42,7 @@ bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos) // Add each set of coords: int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos); - m_Chunks.reserve(NumChunks); + m_Chunks.reserve((size_t)NumChunks); for (int idx = 1; idx <= NumChunks; idx++) { // Push the idx-th element of the array onto stack top, check that it's a table: diff --git a/src/Bindings/LuaFunctions.h b/src/Bindings/LuaFunctions.h index 4f9eab86d..629e2d77d 100644 --- a/src/Bindings/LuaFunctions.h +++ b/src/Bindings/LuaFunctions.h @@ -4,12 +4,12 @@ #include <time.h> // tolua_begin -unsigned int GetTime() +inline unsigned int GetTime() { return (unsigned int)time(0); } -std::string GetChar( std::string & a_Str, unsigned int a_Idx ) +inline std::string GetChar( std::string & a_Str, unsigned int a_Idx ) { return std::string(1, a_Str[ a_Idx ]); } diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index b3f75aff1..10e560ac0 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -37,7 +37,7 @@ /**************************** * Better error reporting for Lua **/ -int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) +static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) { // Retrieve current function name lua_Debug entry; @@ -57,7 +57,7 @@ int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaErro -int lua_do_error(lua_State* L, const char * a_pFormat, ...) +static int lua_do_error(lua_State* L, const char * a_pFormat, ...) { // Retrieve current function name lua_Debug entry; @@ -235,7 +235,7 @@ static int tolua_Base64Decode(lua_State * tolua_S) -cPluginLua * GetLuaPlugin(lua_State * L) +static cPluginLua * GetLuaPlugin(lua_State * L) { // Get the plugin identification out of LuaState: lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME); @@ -1776,20 +1776,20 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) -static int tolua_cPlayer_GetGroups(lua_State* tolua_S) +static int tolua_cPlayer_GetGroups(lua_State * tolua_S) { - cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); const cPlayer::GroupList & AllGroups = self->GetGroups(); - lua_createtable(tolua_S, AllGroups.size(), 0); + lua_createtable(tolua_S, (int)AllGroups.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cPlayer::GroupList::const_iterator iter = AllGroups.begin(); - while(iter != AllGroups.end()) + while (iter != AllGroups.end()) { - const cGroup* Group = *iter; - tolua_pushusertype( tolua_S, (void*)Group, "const cGroup" ); + const cGroup * Group = *iter; + tolua_pushusertype(tolua_S, (void *)Group, "const cGroup"); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; @@ -1801,20 +1801,20 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S) -static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S) +static int tolua_cPlayer_GetResolvedPermissions(lua_State * tolua_S) { - cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); + cPlayer * self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); cPlayer::StringList AllPermissions = self->GetResolvedPermissions(); - lua_createtable(tolua_S, AllPermissions.size(), 0); + lua_createtable(tolua_S, (int)AllPermissions.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cPlayer::StringList::iterator iter = AllPermissions.begin(); - while(iter != AllPermissions.end()) + while (iter != AllPermissions.end()) { - std::string& Permission = *iter; - tolua_pushstring( tolua_S, Permission.c_str() ); + std::string & Permission = *iter; + lua_pushlstring(tolua_S, Permission.c_str(), Permission.length()); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; @@ -2076,18 +2076,18 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S) { - cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S, 1, NULL); + cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, NULL); const cWebAdmin::PluginList & AllPlugins = self->GetPlugins(); - lua_createtable(tolua_S, AllPlugins.size(), 0); + lua_createtable(tolua_S, (int)AllPlugins.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin(); - while(iter != AllPlugins.end()) + while (iter != AllPlugins.end()) { - const cWebPlugin* Plugin = *iter; - tolua_pushusertype( tolua_S, (void*)Plugin, "const cWebPlugin" ); + const cWebPlugin * Plugin = *iter; + tolua_pushusertype(tolua_S, (void *)Plugin, "const cWebPlugin"); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index df0bd4dcc..0bd9270c4 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -56,7 +56,7 @@ public: virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0; virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0; virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; - virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) = 0; + virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index cb55715a6..59708bf59 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -400,14 +400,14 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri -bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Client, a_Reason, cLuaState::Return, res); if (res) { return true; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 59542d23a..3357dd87b 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -79,7 +79,7 @@ public: virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override; virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override; virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; - virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override; + virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 6a5356c0b..fc690d4de 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -143,13 +143,14 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) } } - if (GetNumPlugins() == 0) + size_t NumLoadedPlugins = GetNumPlugins(); + if (NumLoadedPlugins == 0) { LOG("-- No Plugins Loaded --"); } - else if (GetNumPlugins() > 1) + else if (NumLoadedPlugins > 1) { - LOG("-- Loaded %i Plugins --", GetNumPlugins()); + LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); } else { @@ -442,7 +443,7 @@ bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cC -bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason) { HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT); if (Plugins == m_Hooks.end()) @@ -451,7 +452,7 @@ bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Re } for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnDisconnect(a_Player, a_Reason)) + if ((*itr)->OnDisconnect(a_Client, a_Reason)) { return true; } @@ -1869,7 +1870,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) -unsigned int cPluginManager::GetNumPlugins() const +size_t cPluginManager::GetNumPlugins() const { return m_Plugins.size(); } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 512bc1351..3b3091957 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -159,7 +159,7 @@ public: // tolua_export /** Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add */ void AddHook(cPlugin * a_Plugin, int a_HookType); - unsigned int GetNumPlugins() const; // tolua_export + size_t GetNumPlugins() const; // tolua_export // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); @@ -172,7 +172,7 @@ public: // tolua_export bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ); bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup); bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); - bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason); + bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason); bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index e0ae2c5b6..9e20a0983 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -707,11 +707,11 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R if (IsDummyMetas) { - MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); + MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } else { - MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); + MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } } @@ -738,31 +738,31 @@ void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_Block a_DataTypes = a_DataTypes & GetDataTypes(); } - int BlockCount = GetBlockCount(); + size_t BlockCount = GetBlockCount(); if ((a_DataTypes & baTypes) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockTypes[i] = a_BlockType; } } if ((a_DataTypes & baMetas) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockMetas[i] = a_BlockMeta; } } if ((a_DataTypes & baLight) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockLight[i] = a_BlockLight; } } if ((a_DataTypes & baSkyLight) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockSkyLight[i] = a_BlockSkyLight; } diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index def98fdf5..e8d9a7ec4 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -110,10 +110,13 @@ void cBlockInfo::Initialize(void) // 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; @@ -126,6 +129,7 @@ void cBlockInfo::Initialize(void) 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; @@ -196,12 +200,14 @@ void cBlockInfo::Initialize(void) 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; @@ -243,6 +249,7 @@ void cBlockInfo::Initialize(void) 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; @@ -276,6 +283,7 @@ void cBlockInfo::Initialize(void) 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; // Blocks that don't drop without a special tool: @@ -283,6 +291,7 @@ void cBlockInfo::Initialize(void) 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; @@ -325,6 +334,7 @@ void cBlockInfo::Initialize(void) 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; diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 93a796ef7..35a356678 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -23,6 +23,13 @@ public: { a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); } + + + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); + a_Player->OpenWindow(Window); + } virtual bool GetPlacementBlockTypeMeta( diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 92804aaac..51e79b888 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -39,6 +39,13 @@ public: } + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } + + + // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index aa24b8668..2d4fccbac 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -35,8 +35,10 @@ public: // Grass becomes dirt if there is something on top of it: if (a_RelY < cChunkDef::Height - 1) { - BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); - if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above)) || IsBlockWater(Above)) + BLOCKTYPE Above; + NIBBLETYPE AboveMeta; + a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta); + if (!cBlockInfo::GetHandler(Above)->CanDirtGrowGrass(AboveMeta)) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL); return; @@ -77,7 +79,7 @@ public: BLOCKTYPE AboveDest; NIBBLETYPE AboveMeta; Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); - if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest)) + if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta)) { if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread)) { diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index b720ccd14..3dd5bcd1d 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -52,9 +52,9 @@ public: return; } - int NumBlocks = Area.GetBlockCount(); + size_t NumBlocks = Area.GetBlockCount(); BLOCKTYPE * BlockTypes = Area.GetBlockTypes(); - for (int i = 0; i < NumBlocks; i++) + for (size_t i = 0; i < NumBlocks; i++) { if ( (BlockTypes[i] == E_BLOCK_WATER) || diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index c8f158e7e..f9f32eb50 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -68,7 +68,6 @@ public: { return 0; } - for (int newY = Y + 1; newY < cChunkDef::Height; newY++) { @@ -84,7 +83,7 @@ public: // This is because the frame is a solid obsidian pillar if ((MaxY != 0) && (newY == Y + 1)) { - return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface); + return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0; } else { @@ -99,18 +98,18 @@ public: } /// Evaluates if coords have a valid border on top, based on MaxY - int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) + bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) { for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners { if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN) { // Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal - return 0; + return false; } } // Everything was obsidian, found a border! - return -1; // Return -1 for a frame border + return true; } /// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) @@ -169,7 +168,7 @@ public: { return false; // Not valid slice, no portal can be formed } - } XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there + } XZP = X1 - 1; // Set boundary of frame interior for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM) { int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY); @@ -199,13 +198,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZP = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZP = Z1 - 2; + } XZP = Z1 - 1; for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--) { int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY); @@ -213,13 +212,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZM = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZM = Z2 + 2; + } XZM = Z2 + 1; return (FoundFrameZP && FoundFrameZM); } }; diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index d486d642d..d0c4ea55b 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -49,6 +49,12 @@ public: } super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); } + + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return false; + } } ; diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index a764c6f44..304e35e84 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -400,6 +400,15 @@ bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, in +bool cBlockHandler::CanDirtGrowGrass(NIBBLETYPE a_Meta) +{ + return ((cBlockInfo::IsTransparent(m_BlockType)) || (cBlockInfo::IsOneHitDig(m_BlockType))); +} + + + + + bool cBlockHandler::IsUseable() { return false; diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 3a3efb3cc..fb6cae729 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -85,6 +85,9 @@ public: /// Checks if the block can stay at the specified relative coords in the chunk virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); + + /** Can the dirt under this block grow to grass? */ + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta); /** Checks if the block can be placed at this point. Default: CanBeAt(...) diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index d21227b07..495e849fa 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -138,14 +138,14 @@ bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ) { // Filter the blocks into a {leaves, log, other (air)} set: BLOCKTYPE * Types = a_Area.GetBlockTypes(); - for (int i = a_Area.GetBlockCount() - 1; i > 0; i--) + for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) { switch (Types[i]) { - case E_BLOCK_NEW_LEAVES: - case E_BLOCK_NEW_LOG: case E_BLOCK_LEAVES: case E_BLOCK_LOG: + case E_BLOCK_NEW_LEAVES: + case E_BLOCK_NEW_LOG: { break; } diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 21bcbdeea..3b8030028 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "../Mobs/Monster.h" @@ -38,6 +39,19 @@ public: return; // No pickups } + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + cFastRandom Random; + if (Random.NextInt(2000) != 0) + { + return; + } + + int PosX = a_Chunk.GetPosX() * 16 + a_RelX; + int PosZ = a_Chunk.GetPosZ() * 16 + a_RelZ; + + a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, cMonster::mtZombiePigman); + } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 76f5ed0e7..80841b094 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -97,6 +97,12 @@ public: return ""; } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return ((a_Meta & 0x8) != 0); + } + /// Returns true if the specified blocktype is one of the slabs handled by this handler static bool IsAnySlabType(BLOCKTYPE a_BlockType) diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 09ff254a6..a49fda5ae 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -77,6 +77,11 @@ public: // Reset meta to 0 a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Chunk.cpp b/src/Chunk.cpp index cd3bceda2..ca536e89a 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -380,12 +380,12 @@ void cChunk::SetLight( { // Compress blocklight m_BlockLight.clear(); - m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size()]); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size() / 2]); } { // Compress skylight m_BlockSkyLight.clear(); - m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size()]); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size() / 2]); } m_IsLightValid = true; @@ -749,7 +749,7 @@ void cChunk::ProcessQueuedSetBlocks(void) { if (itr->m_Tick <= CurrTick) { - if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to -1 if not specified + if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified { if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType) { @@ -1638,6 +1638,24 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT +void cChunk::SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) +{ + if (GetNibble(m_BlockMeta, a_BlockIdx) == a_Meta) + { + return; + } + + MarkDirty(); + SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); + Vector3i Coords(IndexToCoordinate(a_BlockIdx)); + + m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, Coords.x, Coords.y, Coords.z, GetBlock(a_BlockIdx), a_Meta)); +} + + + + + void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) { // The coords must be valid, because the upper level already does chunk lookup. No need to check them again. diff --git a/src/Chunk.h b/src/Chunk.h index a15d43e00..84ec35496 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -320,10 +320,10 @@ public: m_BlockTickZ = a_RelZ; } - inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); } - inline NIBBLETYPE GetMeta(int a_BlockIdx) const {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); } - inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); } - inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); } + inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const { return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); } + inline NIBBLETYPE GetMeta(int a_BlockIdx) const { return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); } + inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { SetMeta(MakeIndex(a_RelX, a_RelY, a_RelZ), a_Meta); } + void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta); inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ, true); } @@ -420,7 +420,6 @@ private: cWorld * m_World; cChunkMap * m_ChunkMap; - // TODO: Make these pointers and don't allocate what isn't needed COMPRESSED_BLOCKTYPE m_BlockTypes; COMPRESSED_NIBBLETYPE m_BlockMeta; COMPRESSED_NIBBLETYPE m_BlockLight; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 537d491c9..d7164a6a5 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1248,8 +1248,6 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); - Chunk->MarkDirty(); - Chunk->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, NULL); } } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f168a092f..caff15cd0 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -202,7 +202,7 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage { switch (a_ChatPrefix) { - case mtCustom: return AString(); + case mtCustom: return ""; case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White); case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White); case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White); @@ -224,7 +224,7 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage } } ASSERT(!"Unhandled chat prefix type!"); - return AString(); + return ""; } @@ -633,6 +633,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); } + else if (a_Channel == "MC|ItemName") + { + HandleAnvilItemName(a_Message.c_str(), a_Message.size()); + } else if (a_Channel == "REGISTER") { if (HasPluginChannel(a_Channel)) @@ -774,6 +778,29 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Leng +void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length) +{ + if (a_Length < 1) + { + return; + } + + if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil)) + { + return; + } + + AString Name(a_Data, a_Length); + if (Name.length() <= 30) + { + ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player); + } +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", @@ -1510,7 +1537,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason) { LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason); m_HasSentDC = true; Destroy(); @@ -2690,9 +2717,9 @@ void cClientHandle::SocketClosed(void) LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str()); - if (m_Username != "") // Ignore client pings + if (!m_Username.empty()) // Ignore client pings { - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected"); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected"); } Destroy(); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index bddc1dd5e..b6bba4eae 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -385,6 +385,9 @@ private: /** Handles the "MC|AdvCdm" plugin message */ void HandleCommandBlockMessage(const char * a_Data, size_t a_Length); + + /** Handles the "MC|ItemName" plugin message */ + void HandleAnvilItemName(const char * a_Data, size_t a_Length); // cSocketThreads::cCallback overrides: virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index b0af8f271..53a638ee5 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -802,7 +802,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe break; } case E_ITEM_PAPER: break; - default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break; + default: LOG("Unexpected item in firework rocket recipe, was the crafting file's fireworks section changed?"); break; } } } @@ -837,7 +837,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break; case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break; case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break; - default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins + default: LOG("Unexpected item in firework star recipe, was the crafting file's fireworks section changed?"); break; // ermahgerd BARD ardmins } } diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index 38a3c369e..f73a45555 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -109,7 +109,7 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age) WorldAges::iterator itr = m_WorldAges.find(a_WorldName); if (itr == m_WorldAges.end()) { - ASSERT(!"Unknown world in cDeadlockDetect"); + SetWorldAge(a_WorldName, a_Age); return; } diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp index 64f89815b..264878c22 100644 --- a/src/Enchantments.cpp +++ b/src/Enchantments.cpp @@ -83,6 +83,15 @@ void cEnchantments::AddFromString(const AString & a_StringSpec) +size_t cEnchantments::Count(void) +{ + return m_Enchantments.size(); +} + + + + + AString cEnchantments::ToString(void) const { // Serialize all the enchantments into a string diff --git a/src/Enchantments.h b/src/Enchantments.h index ec42257c8..85a316414 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -84,6 +84,9 @@ public: /** Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it */ void AddFromString(const AString & a_StringSpec); + /** Get the count of enchantments */ + size_t Count(void); + /** Serializes all the enchantments into a string */ AString ToString(void) const; diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 847b39bbc..8d2569125 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -15,6 +15,7 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a m_IsCritical(false), m_Timer(0), m_HitGroundTimer(0), + m_HasTeleported(false), m_bIsCollected(false), m_HitBlockPos(Vector3i(0, 0, 0)) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 5c675a387..4cf10a219 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Entity.h" @@ -10,7 +11,6 @@ #include "../Simulator/FluidSimulator.h" #include "../Bindings/PluginManager.h" #include "../Tracer.h" -#include "Minecart.h" #include "Player.h" @@ -32,16 +32,10 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Attachee(NULL) , m_bDirtyHead(true) , m_bDirtyOrientation(true) - , m_bDirtyPosition(true) - , m_bDirtySpeed(true) - , m_bOnGround( false ) - , m_Gravity( -9.81f ) - , m_LastPosX( 0.0 ) - , m_LastPosY( 0.0 ) - , m_LastPosZ( 0.0 ) - , m_TimeLastTeleportPacket(0) - , m_TimeLastMoveReltPacket(0) - , m_TimeLastSpeedPacket(0) + , m_bHasSentNoSpeed(true) + , m_bOnGround(false) + , m_Gravity(-9.81f) + , m_LastPos(a_X, a_Y, a_Z) , m_IsInitialized(false) , m_EntityType(a_EntityType) , m_World(NULL) @@ -55,7 +49,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_IsSubmerged(false) , m_AirLevel(0) , m_AirTickTimer(0) - , m_HeadYaw( 0.0 ) + , m_HeadYaw(0.0) , m_Rot(0.0, 0.0, 0.0) , m_Pos(a_X, a_Y, a_Z) , m_WaterSpeed(0, 0, 0) @@ -794,30 +788,43 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NextSpeed += m_WaterSpeed; - if( NextSpeed.SqrLength() > 0.f ) + if (NextSpeed.SqrLength() > 0.f) { - cTracer Tracer( GetWorld() ); - bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 ); - if (HasHit) // Oh noez! we hit something + cTracer Tracer(GetWorld()); + // Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse + int DistanceToTrace = (int)(ceil((NextSpeed * a_Dt).SqrLength()) * 2); + bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace); + + if (HasHit) { - // Set to hit position + // Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current) + // This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength()) { + // Block hit was within our projected path + // Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1. + // For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f; if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f; if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f; - if (Tracer.HitNormal.y > 0) // means on ground + if (Tracer.HitNormal.y == 1) // Hit BLOCK_FACE_YP, we are on the ground { m_bOnGround = true; } - NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); - NextPos.x += Tracer.HitNormal.x * 0.3f; - NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot - NextPos.z += Tracer.HitNormal.z * 0.3f; + + // Now, set our position to the hit block (i.e. move part way along our intended trajectory) + NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z); + NextPos.x += Tracer.HitNormal.x * 0.1; + NextPos.y += Tracer.HitNormal.y * 0.05; + NextPos.z += Tracer.HitNormal.z * 0.1; } else { + // We have hit a block but overshot our intended trajectory, move normally, safe in the warm cocoon of knowledge that we won't appear to teleport forwards on clients, + // and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never + // be henceforth seen again in the time of programmers and man alike + // </&sensationalist> NextPos += (NextSpeed * a_Dt); } } @@ -1010,9 +1017,9 @@ void cEntity::SetSwimState(cChunk & a_Chunk) { // This sometimes happens on Linux machines // Ref.: http://forum.mc-server.org/showthread.php?tid=1244 - LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}", - RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ() - ); + LOGD("SetSwimState failure: RelX = %d, RelZ = %d, Pos = %.02f, %.02f}", + RelX, RelY, GetPosX(), GetPosZ() + ); m_IsSwimming = false; m_IsSubmerged = false; return; @@ -1178,72 +1185,70 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) { - // Send velocity packet every two ticks if: speed is not negligible or speed was set (as indicated by the DirtySpeed flag) - if (((m_Speed.SqrLength() > 0.0004f) || m_bDirtySpeed) && ((m_World->GetWorldAge() - m_TimeLastSpeedPacket) >= 2)) + // Process packet sending every two ticks + if (GetWorld()->GetWorldAge() % 2 == 0) { - m_World->BroadcastEntityVelocity(*this,a_Exclude); - m_bDirtySpeed = false; - m_TimeLastSpeedPacket = m_World->GetWorldAge(); - } - - // Have to process position related packets this every two ticks - if (m_World->GetWorldAge() % 2 == 0) - { - int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0)); - int DiffY = (int) (floor(GetPosY() * 32.0) - floor(m_LastPosY * 32.0)); - int DiffZ = (int) (floor(GetPosZ() * 32.0) - floor(m_LastPosZ * 32.0)); - Int64 DiffTeleportPacket = m_World->GetWorldAge() - m_TimeLastTeleportPacket; - // 4 blocks is max Relative So if the Diff is greater than 127 or. Send an absolute position every 20 seconds - if (DiffTeleportPacket >= 400 || - ((DiffX > 127) || (DiffX < -128) || - (DiffY > 127) || (DiffY < -128) || - (DiffZ > 127) || (DiffZ < -128))) + double SpeedSqr = GetSpeed().SqrLength(); + if (SpeedSqr == 0.0) { - // - m_World->BroadcastTeleportEntity(*this,a_Exclude); - m_TimeLastTeleportPacket = m_World->GetWorldAge(); - m_TimeLastMoveReltPacket = m_TimeLastTeleportPacket; //Must synchronize. - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_bDirtyPosition = false; - m_bDirtyOrientation = false; + // Speed is zero, send this to clients once only as well as an absolute position + if (!m_bHasSentNoSpeed) + { + m_World->BroadcastEntityVelocity(*this, a_Exclude); + m_World->BroadcastTeleportEntity(*this, a_Exclude); + m_bHasSentNoSpeed = true; + } } else { - Int64 DiffMoveRelPacket = m_World->GetWorldAge() - m_TimeLastMoveReltPacket; - //if the change is big enough. - if ((abs(DiffX) >= 4 || abs(DiffY) >= 4 || abs(DiffZ) >= 4 || DiffMoveRelPacket >= 60) && m_bDirtyPosition) + // Movin' + m_World->BroadcastEntityVelocity(*this, a_Exclude); + m_bHasSentNoSpeed = false; + } + + // TODO: Pickups move disgracefully if relative move packets are sent as opposed to just velocity. Have a system to send relmove only when SetPosXXX() is called with a large difference in position + int DiffX = (int)(floor(GetPosX() * 32.0) - floor(m_LastPos.x * 32.0)); + int DiffY = (int)(floor(GetPosY() * 32.0) - floor(m_LastPos.y * 32.0)); + int DiffZ = (int)(floor(GetPosZ() * 32.0) - floor(m_LastPos.z * 32.0)); + + if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved? + { + if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte { + // Difference within Byte limitations, use a relative move packet if (m_bDirtyOrientation) { - m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude); + m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude); m_bDirtyOrientation = false; } else { - m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude); + m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude); } - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_bDirtyPosition = false; - m_TimeLastMoveReltPacket = m_World->GetWorldAge(); + // Clients seem to store two positions, one for the velocity packet and one for the teleport/relmove packet + // The latter is only changed with a relmove/teleport, and m_LastPos stores this position + m_LastPos = GetPosition(); } else { - if (m_bDirtyOrientation) - { - m_World->BroadcastEntityLook(*this,a_Exclude); - m_bDirtyOrientation = false; - } - } + // Too big a movement, do a teleport + m_World->BroadcastTeleportEntity(*this, a_Exclude); + m_LastPos = GetPosition(); // See above + m_bDirtyOrientation = false; + } } + if (m_bDirtyHead) { - m_World->BroadcastEntityHeadLook(*this,a_Exclude); + m_World->BroadcastEntityHeadLook(*this, a_Exclude); m_bDirtyHead = false; } + if (m_bDirtyOrientation) + { + // Send individual update in case above (sending with rel-move packet) wasn't done + GetWorld()->BroadcastEntityLook(*this, a_Exclude); + m_bDirtyOrientation = false; + } } } @@ -1383,7 +1388,7 @@ void cEntity::SetRoll(double a_Roll) void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) { m_Speed.Set(a_SpeedX, a_SpeedY, a_SpeedZ); - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1393,7 +1398,7 @@ void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) void cEntity::SetSpeedX(double a_SpeedX) { m_Speed.x = a_SpeedX; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1403,7 +1408,7 @@ void cEntity::SetSpeedX(double a_SpeedX) void cEntity::SetSpeedY(double a_SpeedY) { m_Speed.y = a_SpeedY; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1413,7 +1418,7 @@ void cEntity::SetSpeedY(double a_SpeedY) void cEntity::SetSpeedZ(double a_SpeedZ) { m_Speed.z = a_SpeedZ; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1433,7 +1438,7 @@ void cEntity::SetWidth(double a_Width) void cEntity::AddPosX(double a_AddPosX) { m_Pos.x += a_AddPosX; - m_bDirtyPosition = true; + } @@ -1442,7 +1447,7 @@ void cEntity::AddPosX(double a_AddPosX) void cEntity::AddPosY(double a_AddPosY) { m_Pos.y += a_AddPosY; - m_bDirtyPosition = true; + } @@ -1451,7 +1456,7 @@ void cEntity::AddPosY(double a_AddPosY) void cEntity::AddPosZ(double a_AddPosZ) { m_Pos.z += a_AddPosZ; - m_bDirtyPosition = true; + } @@ -1462,7 +1467,7 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ) m_Pos.x += a_AddPosX; m_Pos.y += a_AddPosY; m_Pos.z += a_AddPosZ; - m_bDirtyPosition = true; + } @@ -1472,8 +1477,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed { m_Speed.x += a_AddSpeedX; m_Speed.y += a_AddSpeedY; - m_Speed.z += a_AddSpeedZ; - m_bDirtySpeed = true; + m_Speed.z += a_AddSpeedZ; WrapSpeed(); } @@ -1483,8 +1487,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed void cEntity::AddSpeedX(double a_AddSpeedX) { - m_Speed.x += a_AddSpeedX; - m_bDirtySpeed = true; + m_Speed.x += a_AddSpeedX; WrapSpeed(); } @@ -1494,8 +1497,7 @@ void cEntity::AddSpeedX(double a_AddSpeedX) void cEntity::AddSpeedY(double a_AddSpeedY) { - m_Speed.y += a_AddSpeedY; - m_bDirtySpeed = true; + m_Speed.y += a_AddSpeedY; WrapSpeed(); } @@ -1505,8 +1507,7 @@ void cEntity::AddSpeedY(double a_AddSpeedY) void cEntity::AddSpeedZ(double a_AddSpeedZ) { - m_Speed.z += a_AddSpeedZ; - m_bDirtySpeed = true; + m_Speed.z += a_AddSpeedZ; WrapSpeed(); } @@ -1561,8 +1562,7 @@ Vector3d cEntity::GetLookVector(void) const // Set position void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) { - m_Pos.Set(a_PosX, a_PosY, a_PosZ); - m_bDirtyPosition = true; + m_Pos.Set(a_PosX, a_PosY, a_PosZ); } @@ -1571,8 +1571,7 @@ void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) void cEntity::SetPosX(double a_PosX) { - m_Pos.x = a_PosX; - m_bDirtyPosition = true; + m_Pos.x = a_PosX; } @@ -1581,8 +1580,7 @@ void cEntity::SetPosX(double a_PosX) void cEntity::SetPosY(double a_PosY) { - m_Pos.y = a_PosY; - m_bDirtyPosition = true; + m_Pos.y = a_PosY; } @@ -1592,7 +1590,6 @@ void cEntity::SetPosY(double a_PosY) void cEntity::SetPosZ(double a_PosZ) { m_Pos.z = a_PosZ; - m_bDirtyPosition = true; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index a682701de..df03d635b 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -430,22 +430,29 @@ protected: /// The entity which is attached to this entity (rider), NULL if none cEntity * m_Attachee; - // Flags that signal that we haven't updated the clients with the latest. - bool m_bDirtyHead; - bool m_bDirtyOrientation; - bool m_bDirtyPosition; - bool m_bDirtySpeed; - - bool m_bOnGround; - float m_Gravity; + /** Stores whether head yaw has been set manually */ + bool m_bDirtyHead; + + /** Stores whether our yaw/pitch/roll (body orientation) has been set manually */ + bool m_bDirtyOrientation; - // Last Position. - double m_LastPosX, m_LastPosY, m_LastPosZ; + /** Stores whether we have sent a Velocity packet with a speed of zero (no speed) to the client + Ensures that said packet is sent only once */ + bool m_bHasSentNoSpeed; - // This variables keep track of the last time a packet was sent - Int64 m_TimeLastTeleportPacket, m_TimeLastMoveReltPacket, m_TimeLastSpeedPacket; // In ticks + /** Stores if the entity is on the ground */ + bool m_bOnGround; + + /** Stores gravity that is applied to an entity every tick + For realistic effects, this should be negative. For spaaaaaaace, this can be zero or even positive */ + float m_Gravity; + + /** Last position sent to client via the Relative Move or Teleport packets (not Velocity) + Only updated if cEntity::BroadcastMovementUpdate() is called! */ + Vector3d m_LastPos; - bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() ) + /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */ + bool m_IsInitialized; eEntityType m_EntityType; @@ -469,12 +476,14 @@ protected: /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. int m_TicksSinceLastVoidDamage; + virtual void Destroyed(void) {} // Called after the entity has been destroyed void SetWorld(cWorld * a_World) { m_World = a_World; } /** Called in each tick to handle air-related processing i.e. drowning */ virtual void HandleAir(); + /** Called once per tick to set IsSwimming and IsSubmerged */ virtual void SetSwimState(cChunk & a_Chunk); diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp index 3623c869a..10f79aedc 100644 --- a/src/Entities/ExpOrb.cpp +++ b/src/Entities/ExpOrb.cpp @@ -34,8 +34,6 @@ cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) void cExpOrb::SpawnOn(cClientHandle & a_Client) { a_Client.SendExperienceOrb(*this); - m_bDirtyPosition = false; - m_bDirtySpeed = false; m_bDirtyOrientation = false; m_bDirtyHead = false; } diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index 99bff1100..beb58f207 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -87,9 +87,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) AddSpeedY(MilliDt * -9.8f); AddPosition(GetSpeed() * MilliDt); - // If not static (One billionth precision) broadcast movement. - static const float epsilon = 0.000000001f; - if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon)) + // If not static (one billionth precision) broadcast movement + if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon())) { BroadcastMovementUpdate(); } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 08b7d3984..6ac11c270 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -76,11 +76,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) cTimer t1; m_LastPlayerListTime = t1.GetNowTime(); - - m_TimeLastTeleportPacket = 0; m_PlayerName = a_PlayerName; - m_bDirtyPosition = true; // So chunks are streamed to player at spawn if (!LoadFromDisk()) { @@ -209,25 +206,22 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) m_BowCharge += 1; } - //handle updating experience + // Handle updating experience if (m_bDirtyExperience) { SendExperience(); } - if (m_bDirtyPosition) + if (GetPosition() != m_LastPos) // Change in position from last tick? { // Apply food exhaustion from movement: ApplyFoodExhaustionFromMovement(); cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this); - BroadcastMovementUpdate(m_ClientHandle); m_ClientHandle->StreamChunks(); } - else - { - BroadcastMovementUpdate(m_ClientHandle); - } + + BroadcastMovementUpdate(m_ClientHandle); if (m_Health > 0) // make sure player is alive { @@ -1596,10 +1590,7 @@ bool cPlayer::LoadFromDisk() SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_LastFoodPos = GetPosition(); + m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; @@ -1860,17 +1851,16 @@ void cPlayer::ApplyFoodExhaustionFromMovement() { return; } - - // Calculate the distance travelled, update the last pos: - Vector3d Movement(GetPosition() - m_LastFoodPos); - Movement.y = 0; // Only take XZ movement into account - m_LastFoodPos = GetPosition(); - + // If riding anything, apply no food exhaustion if (m_AttachedTo != NULL) { return; } + + // Calculate the distance travelled, update the last pos: + Vector3d Movement(GetPosition() - m_LastPos); + Movement.y = 0; // Only take XZ movement into account // Apply the exhaustion based on distance travelled: double BaseExhaustion = Movement.Length(); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 3029abfe0..6fc7e2875 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -423,9 +423,6 @@ protected: /** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */ int m_FoodPoisonedTicksRemaining; - /** Last position that has been recorded for food-related processing: */ - Vector3d m_LastFoodPos; - float m_LastJumpHeight; float m_LastGroundHeight; bool m_bTouchGround; diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp index 02f31f5bb..fd9a4e7ac 100644 --- a/src/Entities/TNTEntity.cpp +++ b/src/Entities/TNTEntity.cpp @@ -30,8 +30,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) : void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle) { a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT - m_bDirtyPosition = false; - m_bDirtySpeed = false; m_bDirtyOrientation = false; m_bDirtyHead = false; } diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 5cad11d2a..872e3341d 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -35,13 +35,6 @@ reduced in complexity in order for this generator to be useful, so the caves' sh -/// How many nests in each direction are generated for a given chunk. Must be an even number -#define NEIGHBORHOOD_SIZE 8 - - - - - const int MIN_RADIUS = 3; const int MAX_RADIUS = 8; @@ -122,27 +115,19 @@ typedef std::vector<cCaveTunnel *> cCaveTunnels; /// A collection of connected tunnels, possibly branching. -class cStructGenWormNestCaves::cCaveSystem +class cStructGenWormNestCaves::cCaveSystem : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + public: // The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk() int m_BlockX; int m_BlockZ; - cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); + cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); ~cCaveSystem(); - /// Carves the cave system into the chunk specified - void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap - ); - - #ifdef _DEBUG - AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; - #endif // _DEBUG - protected: int m_Size; cCaveTunnels m_Tunnels; @@ -157,6 +142,9 @@ protected: /// Returns a radius based on the location provided. int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ); + + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override; } ; @@ -239,9 +227,15 @@ void cCaveTunnel::Randomize(cNoise & a_Noise) bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst) { + if (a_Src.size() < 2) + { + // There are no midpoints, nothing to smooth + return true; + } + // Smoothing: for each line segment, add points on its 1/4 lengths bool res = false; - int Num = a_Src.size() - 2; // this many intermediary points + size_t Num = a_Src.size() - 2; // this many intermediary points a_Dst.clear(); a_Dst.reserve(Num * 2 + 2); cCaveDefPoints::const_iterator itr = a_Src.begin() + 1; @@ -251,7 +245,7 @@ bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & int PrevY = Source.m_BlockY; int PrevZ = Source.m_BlockZ; int PrevR = Source.m_Radius; - for (int i = 0; i <= Num; ++i, ++itr) + for (size_t i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; int dy = itr->m_BlockY - PrevY; @@ -580,17 +574,16 @@ AString cCaveTunnel::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) cons /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenWormNestCaves::cCaveSystem: -cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ), +cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) : + super(a_OriginX, a_OriginZ), m_Size(a_Size) { - int Num = 1 + a_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) % 3; + int Num = 1 + a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) % 3; for (int i = 0; i < Num; i++) { - int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset; - int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset; - int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20; + int OriginX = a_OriginX + (a_Noise.IntNoise3DInt(13 * a_OriginX, 17 * a_OriginZ, 11 * i) / 19) % a_MaxOffset; + int OriginZ = a_OriginZ + (a_Noise.IntNoise3DInt(17 * a_OriginX, 13 * a_OriginZ, 11 * i) / 23) % a_MaxOffset; + int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_OriginX, 13 * a_OriginZ, 11 * i) / 17) % 20; // Generate three branches from the origin point: // The tunnels generated depend on X, Y, Z and Branches, @@ -616,64 +609,17 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem() -void cStructGenWormNestCaves::cCaveSystem::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap -) -{ - for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr) - { - (*itr)->ProcessChunk(a_ChunkX, a_ChunkZ, a_BlockTypes, a_HeightMap); - } // for itr - m_Tunnels[] -} - - - - - -#ifdef _DEBUG -AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const +void cStructGenWormNestCaves::cCaveSystem::DrawIntoChunk(cChunkDesc & a_ChunkDesc) { - AString SVG; - SVG.reserve(512 * 1024); + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); + cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap(); for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr) { - SVG.append((*itr)->ExportAsSVG(a_Color, a_OffsetX, a_OffsetZ)); + (*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, HeightMap); } // for itr - m_Tunnels[] - - // Base point highlight: - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ - ); - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 - ); - - // A gray line from the base point to the first point of the ravine, for identification: - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, - a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, - a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ - ); - - // Offset guides: - if (a_OffsetX > 0) - { - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M %d,0 L %d,1024\"/>\n", - a_OffsetX, a_OffsetX - ); - } - if (a_OffsetZ > 0) - { - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M 0,%d L 1024,%d\"/>\n", - a_OffsetZ, a_OffsetZ - ); - } - - return SVG; } -#endif // _DEBUG @@ -744,142 +690,9 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenWormNestCaves: -cStructGenWormNestCaves::~cStructGenWormNestCaves() -{ - ClearCache(); -} - - - - - -void cStructGenWormNestCaves::ClearCache(void) +cGridStructGen::cStructurePtr cStructGenWormNestCaves::CreateStructure(int a_OriginX, int a_OriginZ) { - for (cCaveSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cCaveSystems Caves; - GetCavesForChunk(ChunkX, ChunkZ, Caves); - for (cCaveSystems::const_iterator itr = Caves.begin(); itr != Caves.end(); ++itr) - { - (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - } // for itr - Caves[] -} - - - - - -void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenWormNestCaves::cCaveSystems & a_Caves) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_Grid; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_Grid; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= NEIGHBORHOOD_SIZE / 2; - BaseZ -= NEIGHBORHOOD_SIZE / 2; - - // Walk the cache, move each cave system that we want into a_Caves: - int StartX = BaseX * m_Grid; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Grid; - int StartZ = BaseZ * m_Grid; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Grid; - for (cCaveSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_Caves.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_Grid; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_Grid; - bool Found = false; - for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } - if (!Found) - { - a_Caves.push_back(new cCaveSystem(RealX, RealZ, m_MaxOffset, m_Size, m_Noise)); - } - } - } - - // Copy a_Caves into m_Cache to the beginning: - cCaveSystems CavesCopy(a_Caves); - m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cCaveSystems::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cCaveSystems::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } - - /* - // Uncomment this block for debugging the caves' shapes in 2D using an SVG export - #ifdef _DEBUG - AString SVG; - SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n"); - SVG.reserve(2 * 1024 * 1024); - for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr) - { - int Color = 0x10 * abs((*itr)->m_BlockX / m_Grid); - Color |= 0x1000 * abs((*itr)->m_BlockZ / m_Grid); - SVG.append((*itr)->ExportAsSVG(Color, 512, 512)); - } - SVG.append("</svg>\n"); - - AString fnam; - Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); - cFile File(fnam, cFile::fmWrite); - File.Write(SVG.c_str(), SVG.size()); - #endif // _DEBUG - //*/ + return cStructurePtr(new cCaveSystem(a_OriginX, a_OriginZ, m_MaxOffset, m_Size, m_Noise)); } diff --git a/src/Generating/Caves.h b/src/Generating/Caves.h index 7c45c056b..254dcddbd 100644 --- a/src/Generating/Caves.h +++ b/src/Generating/Caves.h @@ -12,7 +12,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -64,10 +64,12 @@ protected: class cStructGenWormNestCaves : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; public: cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) : + super(a_Seed, a_Grid, a_Grid, a_Size + a_MaxOffset, a_Size + a_MaxOffset, 100), m_Noise(a_Seed), m_Size(a_Size), m_MaxOffset(a_MaxOffset), @@ -75,26 +77,16 @@ public: { } - ~cStructGenWormNestCaves(); - protected: class cCaveSystem; // fwd: Caves.cpp - typedef std::list<cCaveSystem *> cCaveSystems; cNoise m_Noise; int m_Size; // relative size of the cave systems' caves. Average number of blocks of each initial tunnel int m_MaxOffset; // maximum offset of the cave nest origin from the grid cell the nest belongs to int m_Grid; // average spacing of the nests - cCaveSystems m_Cache; - - /// Clears everything from the cache - void ClearCache(void); - - /// Returns all caves that *may* intersect the given chunk. All the caves are valid until the next call to this function. - void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves); - - // cStructGen override: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // cGridStructGen override: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/GridStructGen.cpp b/src/Generating/GridStructGen.cpp new file mode 100644 index 000000000..3bbc89054 --- /dev/null +++ b/src/Generating/GridStructGen.cpp @@ -0,0 +1,126 @@ + +// GridStructGen.cpp + +// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid + +#include "Globals.h" +#include "GridStructGen.h" + + + + +cGridStructGen::cGridStructGen( + int a_Seed, + int a_GridSizeX, int a_GridSizeZ, + int a_MaxStructureSizeX, int a_MaxStructureSizeZ, + size_t a_MaxCacheSize +) : + m_Seed(a_Seed), + m_GridSizeX(a_GridSizeX), + m_GridSizeZ(a_GridSizeZ), + m_MaxStructureSizeX(a_MaxStructureSizeX), + m_MaxStructureSizeZ(a_MaxStructureSizeZ), + m_MaxCacheSize(a_MaxCacheSize) +{ +} + + + + + +void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures) +{ + // Calculate the min and max grid coords of the structures to be returned: + int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX; + int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ; + int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + cChunkDef::Width - 1; + int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + cChunkDef::Width - 1; + int MinGridX = MinBlockX / m_GridSizeX; + int MinGridZ = MinBlockZ / m_GridSizeZ; + int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX; + int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ; + int MinX = MinGridX * m_GridSizeX; + int MaxX = MaxGridX * m_GridSizeX; + int MinZ = MinGridZ * m_GridSizeZ; + int MaxZ = MaxGridZ * m_GridSizeZ; + + // Walk the cache, move each structure that we want into a_Structures: + for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) + { + if ( + ((*itr)->m_OriginX >= MinX) && ((*itr)->m_OriginX < MaxX) && + ((*itr)->m_OriginZ >= MinZ) && ((*itr)->m_OriginZ < MaxZ) + ) + { + // want + a_Structures.push_back(*itr); + itr = m_Cache.erase(itr); + } + else + { + // don't want + ++itr; + } + } // for itr - m_Cache[] + + // Create those structures that haven't been in the cache: + for (int x = MinGridX; x < MaxGridX; x++) + { + int OriginX = x * m_GridSizeX; + for (int z = MinGridZ; z < MaxGridZ; z++) + { + int OriginZ = z * m_GridSizeZ; + bool Found = false; + for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr) + { + if (((*itr)->m_OriginX == OriginX) && ((*itr)->m_OriginZ == OriginZ)) + { + Found = true; + break; + } + } // for itr - a_Structures[] + if (!Found) + { + a_Structures.push_back(CreateStructure(OriginX, OriginZ)); + } + } // for z + } // for x + + // Copy a_Forts into m_Cache to the beginning: + cStructurePtrs StructuresCopy (a_Structures); + m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end()); + + // Trim the cache if it's too long: + size_t CacheSize = 0; + for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) + { + CacheSize += (*itr)->GetCacheCost(); + if (CacheSize > m_MaxCacheSize) + { + // Erase all items from this one till the cache end + m_Cache.erase(itr, m_Cache.end()); + break; + } + } +} + + + + + +void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc) +{ + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + cStructurePtrs Structures; + GetStructuresForChunk(ChunkX, ChunkZ, Structures); + for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr) + { + (*itr)->DrawIntoChunk(a_ChunkDesc); + } // for itr - Structures[] +} + + + + + diff --git a/src/Generating/GridStructGen.h b/src/Generating/GridStructGen.h new file mode 100644 index 000000000..234cc75c5 --- /dev/null +++ b/src/Generating/GridStructGen.h @@ -0,0 +1,124 @@ + +// GridStructGen.h + +// Declares the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid + + + + + +#pragma once + +#include "ComposableGenerator.h" + + + + + +/** Generates structures in a semi-random grid. +Defines a grid in the XZ space with predefined cell size in each direction. Each cell then receives exactly +one structure (provided by the descendant class). The structure is placed within the cell, but doesn't need +to be bounded by the cell, it can be well outside the cell; the generator uses the MaxStructureSize parameter +to determine how far away from the cell the structure can be at most. +This class provides a cache for the structures generated for successive chunks and manages that cache. It +also provides the cFinishGen override that uses the cache to actually generate the structure into chunk data. + +After generating each chunk the cache is checked for size, each item in the cache has a cost associated with +it and the cache is trimmed (from its least-recently-used end) so that the sum of the cost in the cache is +less than m_MaxCacheSize + +To use this class, declare a descendant class that implements the overridable methods, then create an +instance of that class. The descendant must provide the CreateStructure() function that is called to generate +a structure at the specific grid cell. + +The descendant must use a specific cStructure descendant to provide the actual structure that gets generated. +The structure must provide the DrawIntoChunk() function that generates the structure into the chunk data, and +can override the GetCacheCost() function that returns the cost of that structure in the cache. +*/ +class cGridStructGen : + public cFinishGen +{ +public: + cGridStructGen( + int a_Seed, + int a_GridSizeX, int a_GridSizeZ, + int a_MaxStructureSizeX, int a_MaxStructureSizeZ, + size_t a_MaxCacheSize + ); + +protected: + /** Represents a single structure that occupies the grid point. Knows how to draw itself into a chunk. */ + class cStructure + { + public: + /** The origin (the coords of the gridpoint for which the structure is generated) */ + int m_OriginX, m_OriginZ; + + + /** Creates a structure that has its originset at the specified coords. */ + cStructure (int a_OriginX, int a_OriginZ) : + m_OriginX(a_OriginX), + m_OriginZ(a_OriginZ) + { + } + + // Force a virtual destructor in descendants: + virtual ~cStructure() {} + + /** Draws self into the specified chunk */ + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) = 0; + + /** Returns the cost of keeping this structure in the cache */ + virtual size_t GetCacheCost(void) const { return 1; } + } ; + typedef SharedPtr<cStructure> cStructurePtr; + typedef std::list<cStructurePtr> cStructurePtrs; + + + /** Seed for generating the semi-random grid. */ + int m_Seed; + + /** The size of each grid's cell in the X axis */ + int m_GridSizeX; + + /** The size of each grid's cell in the Z axis */ + int m_GridSizeZ; + + /** Maximum theoretical size of the structure in the X axis. + This limits the structures considered for a single chunk, so the lesser the number, the better performance. + Structures large than this may get cropped. */ + int m_MaxStructureSizeX; + + /** Maximum theoretical size of the structure in the Z axis. + This limits the structures considered for a single chunk, so the lesser the number, the better performance. + Structures large than this may get cropped. */ + int m_MaxStructureSizeZ; + + /** Maximum allowed sum of costs for items in the cache. Items that are over this cost are removed from the + cache, oldest-first */ + size_t m_MaxCacheSize; + + /** Cache for the most recently generated structures, ordered by the recentness. */ + cStructurePtrs m_Cache; + + + /** Clears everything from the cache */ + void ClearCache(void); + + /** Returns all structures that may intersect the given chunk. + The structures are considered as intersecting iff their bounding box (defined by m_MaxStructureSize) + around their gridpoint intersects the chunk. */ + void GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures); + + // cFinishGen overrides: + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // Functions for the descendants to override: + /** Create a new structure at the specified gridpoint */ + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) = 0; +} ; + + + + + diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 231295c3f..391e4c04f 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -25,12 +25,6 @@ in a depth-first processing. Each of the descendants will branch randomly, if no -static const int NEIGHBORHOOD_SIZE = 3; - - - - - class cMineShaft abstract { public: @@ -234,10 +228,12 @@ protected: -class cStructGenMineShafts::cMineShaftSystem +class cStructGenMineShafts::cMineShaftSystem : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + public: - int m_BlockX, m_BlockZ; ///< The pivot point on which the system is generated int m_GridSize; ///< Maximum offset of the dirtroom from grid center, * 2, in each direction int m_MaxRecursion; ///< Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion) int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor @@ -249,17 +245,15 @@ public: cMineShafts m_MineShafts; ///< List of cMineShaft descendants that comprise this system cCuboid m_BoundingBox; ///< Bounding box into which all of the components need to fit - /// Creates and generates the entire system + + /** Creates and generates the entire system */ cMineShaftSystem( - int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, + int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase ); ~cMineShaftSystem(); - /// Carves the system into the chunk data - void ProcessChunk(cChunkDesc & a_Chunk); - /** Creates new cMineShaft descendant connected at the specified point, heading the specified direction, if it fits, appends it to the list and calls its AppendBranches() */ @@ -269,8 +263,11 @@ public: int a_RecursionLevel ); - /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid + /** Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid */ bool CanAppend(const cCuboid & a_BoundingBox); + + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_Chunk); } ; @@ -281,11 +278,10 @@ public: // cStructGenMineShafts::cMineShaftSystem: cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( - int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, + int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase ) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ), + super(a_OriginX, a_OriginZ), m_GridSize(a_GridSize), m_MaxRecursion(8), // TODO: settable m_ProbLevelCorridor(a_ProbLevelCorridor), @@ -330,7 +326,7 @@ cStructGenMineShafts::cMineShaftSystem::~cMineShaftSystem() -void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk) +void cStructGenMineShafts::cMineShaftSystem::DrawIntoChunk(cChunkDesc & a_Chunk) { for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { @@ -409,15 +405,15 @@ cMineShaftDirtRoom::cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & super(a_Parent, mskDirtRoom) { // Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18: - int rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 0, a_Parent.m_BlockZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 0, a_Parent.m_OriginZ) / 7; int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2; rnd >>= 12; int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2; - rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 1000, a_Parent.m_BlockZ) / 11; - m_BoundingBox.p1.x = a_Parent.m_BlockX + OfsX; + rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 1000, a_Parent.m_OriginZ) / 11; + m_BoundingBox.p1.x = a_Parent.m_OriginX + OfsX; m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8); rnd >>= 4; - m_BoundingBox.p1.z = a_Parent.m_BlockZ + OfsZ; + m_BoundingBox.p1.z = a_Parent.m_OriginZ + OfsZ; m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8); rnd >>= 4; m_BoundingBox.p1.y = 20; @@ -543,7 +539,7 @@ cMineShaft * cMineShaftCorridor::CreateAndFit( { cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ); BoundingBox.p2.y += 3; - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; int NumSegments = 2 + (rnd) % (MAX_SEGMENTS - 1); // 2 .. MAX_SEGMENTS switch (a_Direction) { @@ -985,7 +981,7 @@ cMineShaft * cMineShaftCrossing::CreateAndFit( ) { cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ); - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; BoundingBox.p2.y += 3; if ((rnd % 4) < 2) { @@ -1127,7 +1123,7 @@ cMineShaft * cMineShaftStaircase::CreateAndFit( cNoise & a_Noise ) { - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; cCuboid Box; switch (a_Direction) { @@ -1287,6 +1283,7 @@ cStructGenMineShafts::cStructGenMineShafts( int a_Seed, int a_GridSize, int a_MaxSystemSize, int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase ) : + super(a_Seed, a_GridSize, a_GridSize, 120 + a_MaxSystemSize * 10, 120 + a_MaxSystemSize * 10, 100), m_Noise(a_Seed), m_GridSize(a_GridSize), m_MaxSystemSize(a_MaxSystemSize), @@ -1300,125 +1297,9 @@ cStructGenMineShafts::cStructGenMineShafts( -cStructGenMineShafts::~cStructGenMineShafts() -{ - ClearCache(); -} - - - - - -void cStructGenMineShafts::ClearCache(void) -{ - for (cMineShaftSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenMineShafts::GetMineShaftSystemsForChunk( - int a_ChunkX, int a_ChunkZ, - cStructGenMineShafts::cMineShaftSystems & a_MineShafts -) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= NEIGHBORHOOD_SIZE / 2; - BaseZ -= NEIGHBORHOOD_SIZE / 2; - - // Walk the cache, move each cave system that we want into a_Mineshafts: - int StartX = BaseX * m_GridSize; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - int StartZ = BaseZ * m_GridSize; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - for (cMineShaftSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_MineShafts.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_GridSize; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_GridSize; - bool Found = false; - for (cMineShaftSystems::const_iterator itr = a_MineShafts.begin(), end = a_MineShafts.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } // for itr - a_Mineshafts - if (!Found) - { - a_MineShafts.push_back(new cMineShaftSystem(RealX, RealZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase)); - } - } // for z - } // for x - - // Copy a_MineShafts into m_Cache to the beginning: - cMineShaftSystems MineShaftsCopy(a_MineShafts); - m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cMineShaftSystems::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cMineShaftSystems::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } -} - - - - - - -void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc) +cGridStructGen::cStructurePtr cStructGenMineShafts::CreateStructure(int a_OriginX, int a_OriginZ) { - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cMineShaftSystems MineShafts; - GetMineShaftSystemsForChunk(ChunkX, ChunkZ, MineShafts); - for (cMineShaftSystems::const_iterator itr = MineShafts.begin(); itr != MineShafts.end(); ++itr) - { - (*itr)->ProcessChunk(a_ChunkDesc); - } // for itr - MineShafts[] + return cStructurePtr(new cMineShaftSystem(a_OriginX, a_OriginZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase)); } diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h index ba32e75ad..c29b6cdac 100644 --- a/src/Generating/MineShafts.h +++ b/src/Generating/MineShafts.h @@ -9,7 +9,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -17,16 +17,16 @@ class cStructGenMineShafts : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; + public: cStructGenMineShafts( int a_Seed, int a_GridSize, int a_MaxSystemSize, int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase ); - virtual ~cStructGenMineShafts(); - protected: friend class cMineShaft; friend class cMineShaftDirtRoom; @@ -34,26 +34,16 @@ protected: friend class cMineShaftCrossing; friend class cMineShaftStaircase; class cMineShaftSystem; // fwd: MineShafts.cpp - typedef std::list<cMineShaftSystem *> cMineShaftSystems; - cNoise m_Noise; - int m_GridSize; ///< Average spacing of the systems - int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system - int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor - int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor - int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing - cMineShaftSystems m_Cache; ///< Cache of the most recently used systems. MoveToFront used. + cNoise m_Noise; + int m_GridSize; ///< Average spacing of the systems + int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system + int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor + int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor + int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing - /// Clears everything from the cache - void ClearCache(void); - - /** Returns all systems that *may* intersect the given chunk. - All the systems are valid until the next call to this function (which may delete some of the pointers). - */ - void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems); - - // cFinishGen overrides: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp index d90fdeb0a..3867ec80c 100644 --- a/src/Generating/NetherFortGen.cpp +++ b/src/Generating/NetherFortGen.cpp @@ -11,29 +11,24 @@ -static const int NEIGHBORHOOD_SIZE = 3; - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cNetherFortGen::cNetherFort: -class cNetherFortGen::cNetherFort +class cNetherFortGen::cNetherFort : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + public: cNetherFortGen & m_ParentGen; - int m_BlockX, m_BlockZ; int m_GridSize; int m_Seed; cPlacedPieces m_Pieces; - cNetherFort(cNetherFortGen & a_ParentGen, int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxDepth, int a_Seed) : + cNetherFort(cNetherFortGen & a_ParentGen, int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxDepth, int a_Seed) : + super(a_OriginX, a_OriginZ), m_ParentGen(a_ParentGen), - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ), m_GridSize(a_GridSize), m_Seed(a_Seed) { @@ -43,8 +38,8 @@ public: // Generate pieces: for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++) { - cBFSPieceGenerator pg(m_ParentGen, a_Seed + i); - pg.PlacePieces(a_BlockX, BlockY, a_BlockZ, a_MaxDepth, m_Pieces); + cBFSPieceGenerator pg(cNetherFortGen::m_PiecePool, a_Seed + i); + pg.PlacePieces(a_OriginX, BlockY, a_OriginZ, a_MaxDepth, m_Pieces); } } @@ -56,7 +51,7 @@ public: /** Carves the system into the chunk data */ - void ProcessChunk(cChunkDesc & a_Chunk) + virtual void DrawIntoChunk(cChunkDesc & a_Chunk) { for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) { @@ -107,214 +102,30 @@ public: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cNetherFortGen: +cPrefabPiecePool cNetherFortGen::m_PiecePool(g_NetherFortPrefabs, g_NetherFortPrefabsCount, g_NetherFortStartingPrefabs, g_NetherFortStartingPrefabsCount); + + + + + cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) : - m_Seed(a_Seed), - m_Noise(a_Seed), - m_GridSize(a_GridSize), + super(a_Seed, a_GridSize, a_GridSize, a_MaxDepth * 10, a_MaxDepth * 10, 200), m_MaxDepth(a_MaxDepth) { - // Initialize the prefabs: - for (size_t i = 0; i < g_NetherFortPrefabsCount; i++) - { - cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs[i]); - m_AllPieces.push_back(Prefab); - if (Prefab->HasConnectorType(0)) - { - m_OuterPieces.push_back(Prefab); - } - if (Prefab->HasConnectorType(1)) - { - m_InnerPieces.push_back(Prefab); - } - } - - // Initialize the starting piece prefabs: - for (size_t i = 0; i < g_NetherFortStartingPrefabsCount; i++) - { - m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs[i])); - } - /* // DEBUG: Try one round of placement: cPlacedPieces Pieces; - cBFSPieceGenerator pg(*this, a_Seed); + cBFSPieceGenerator pg(m_PiecePool, a_Seed); pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces); - */ -} - - - - - -cNetherFortGen::~cNetherFortGen() -{ - ClearCache(); - for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_AllPieces[] - m_AllPieces.clear(); -} - - - - - -void cNetherFortGen::ClearCache(void) -{ - // TODO -} - - - - - -void cNetherFortGen::GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= NEIGHBORHOOD_SIZE / 2; - BaseZ -= NEIGHBORHOOD_SIZE / 2; - - // Walk the cache, move each cave system that we want into a_Forts: - int StartX = BaseX * m_GridSize; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - int StartZ = BaseZ * m_GridSize; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - for (cNetherForts::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_Forts.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - // Create those forts that haven't been in the cache: - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_GridSize; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_GridSize; - bool Found = false; - for (cNetherForts::const_iterator itr = a_Forts.begin(), end = a_Forts.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } // for itr - a_Mineshafts - if (!Found) - { - a_Forts.push_back(new cNetherFort(*this, RealX, RealZ, m_GridSize, m_MaxDepth, m_Seed)); - } - } // for z - } // for x - - // Copy a_Forts into m_Cache to the beginning: - cNetherForts FortsCopy (a_Forts); - m_Cache.splice(m_Cache.begin(), FortsCopy, FortsCopy.begin(), FortsCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cNetherForts::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cNetherForts::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } -} - - - - - -void cNetherFortGen::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cNetherForts Forts; - GetFortsForChunk(ChunkX, ChunkZ, Forts); - for (cNetherForts::const_iterator itr = Forts.begin(); itr != Forts.end(); ++itr) - { - (*itr)->ProcessChunk(a_ChunkDesc); - } // for itr - Forts[] -} - - - - - -cPieces cNetherFortGen::GetPiecesWithConnector(int a_ConnectorType) -{ - switch (a_ConnectorType) - { - case 0: return m_OuterPieces; - case 1: return m_InnerPieces; - default: return cPieces(); - } + //*/ } -cPieces cNetherFortGen::GetStartingPieces(void) +cGridStructGen::cStructurePtr cNetherFortGen::CreateStructure(int a_OriginX, int a_OriginZ) { - return m_StartingPieces; + return cStructurePtr(new cNetherFort(*this, a_OriginX, a_OriginZ, m_GridSizeX, m_MaxDepth, m_Seed)); } - - - - -int cNetherFortGen::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) -{ - return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); -} - - - - - -void cNetherFortGen::PiecePlaced(const cPiece & a_Piece) -{ - UNUSED(a_Piece); -} - - - - - -void cNetherFortGen::Reset(void) -{ - // Nothing needed -} - - - - diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h index d51596b9e..f35801a3c 100644 --- a/src/Generating/NetherFortGen.h +++ b/src/Generating/NetherFortGen.h @@ -10,77 +10,34 @@ #pragma once #include "ComposableGenerator.h" -#include "PieceGenerator.h" +#include "PrefabPiecePool.h" +#include "GridStructGen.h" class cNetherFortGen : - public cFinishGen, - public cPiecePool + public cGridStructGen { + typedef cGridStructGen super; + public: cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth); - virtual ~cNetherFortGen(); - protected: friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp class cNetherFort; // fwd: NetherFortGen.cpp - typedef std::list<cNetherFort *> cNetherForts; - - - /** The seed used for generating*/ - int m_Seed; - - /** The noise used for generating */ - cNoise m_Noise; - - /** Average spacing between the fortresses*/ - int m_GridSize; /** Maximum depth of the piece-generator tree */ int m_MaxDepth; - - /** Cache of the most recently used systems. MoveToFront used. */ - cNetherForts m_Cache; - /** All the pieces that are allowed for building. - This is the list that's used for memory allocation and deallocation for the pieces. */ - cPieces m_AllPieces; + /** The pool of pieces to use for generating. Static, so that it's shared by multiple generators. */ + static cPrefabPiecePool m_PiecePool; - /** The pieces that are used as starting pieces. - This list is not shared and the pieces need deallocation. */ - cPieces m_StartingPieces; - - /** The pieces that have an "outer" connector. - The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ - cPieces m_OuterPieces; - - /** The pieces that have an "inner" connector. - The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ - cPieces m_InnerPieces; - - /** Clears everything from the cache. - Also invalidates the forst returned by GetFortsForChunk(). */ - void ClearCache(void); - - /** Returns all forts that *may* intersect the given chunk. - The returned forts live within m_Cache.They are valid until the next call - to this function (which may delete some of the pointers). */ - void GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts); - - // cFinishGen overrides: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; - - // cPiecePool overrides: - virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; - virtual cPieces GetStartingPieces(void) override; - virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override; - virtual void PiecePlaced(const cPiece & a_Piece) override; - virtual void Reset(void) override; + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index 8e9a48be6..ce19c1c95 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -339,9 +339,9 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i int NumRotations = 1; for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++) { - if (StartingPiece->CanRotateCCW(i)) + if (StartingPiece->CanRotateCCW((int)i)) { - Rotations[NumRotations] = i; + Rotations[NumRotations] = (int)i; NumRotations += 1; } } @@ -388,7 +388,8 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // Get a list of available connections: const int * RotTable = DirectionRotationTable[a_Connector.m_Direction]; cConnections Connections; - cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type); + int WantedConnectorType = -a_Connector.m_Type; + cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType); Connections.reserve(AvailablePieces.size()); Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction); @@ -406,7 +407,7 @@ bool cPieceGenerator::TryPlacePieceAtConnector( cPiece::cConnectors Connectors = (*itrP)->GetConnectors(); for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC) { - if (itrC->m_Type != a_Connector.m_Type) + if (itrC->m_Type != WantedConnectorType) { continue; } diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index f4433b947..16bec3bb4 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -38,7 +38,8 @@ public: /** Position relative to the piece */ Vector3i m_Pos; - /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */ + /** Type of the connector. Any arbitrary number; the generator connects only connectors of opposite + (negative) types. */ int m_Type; /** Direction in which the connector is facing. diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index 44d5097de..0f20603be 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -174,44 +174,47 @@ void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy); // If requested, draw the floor (from the bottom of the prefab down to the nearest non-air) - int MaxX = Image.GetSizeX(); - int MaxZ = Image.GetSizeZ(); - for (int z = 0; z < MaxZ; z++) + if (m_ShouldExtendFloor) { - int RelZ = Placement.z + z; - if ((RelZ < 0) || (RelZ >= cChunkDef::Width)) + int MaxX = Image.GetSizeX(); + int MaxZ = Image.GetSizeZ(); + for (int z = 0; z < MaxZ; z++) { - // Z coord outside the chunk - continue; - } - for (int x = 0; x < MaxX; x++) - { - int RelX = Placement.x + x; - if ((RelX < 0) || (RelX >= cChunkDef::Width)) - { - // X coord outside the chunk - continue; - } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - Image.GetRelBlockTypeMeta(x, 0, z, BlockType, BlockMeta); - if ((BlockType == E_BLOCK_AIR) || (BlockType == E_BLOCK_SPONGE)) + int RelZ = Placement.z + z; + if ((RelZ < 0) || (RelZ >= cChunkDef::Width)) { - // Do not expand air nor sponge blocks + // Z coord outside the chunk continue; } - for (int y = Placement.y - 1; y >= 0; y--) + for (int x = 0; x < MaxX; x++) { - BLOCKTYPE ExistingBlock = a_Dest.GetBlockType(RelX, y, RelZ); - if (ExistingBlock != E_BLOCK_AIR) + int RelX = Placement.x + x; + if ((RelX < 0) || (RelX >= cChunkDef::Width)) + { + // X coord outside the chunk + continue; + } + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + Image.GetRelBlockTypeMeta(x, 0, z, BlockType, BlockMeta); + if ((BlockType == E_BLOCK_AIR) || (BlockType == E_BLOCK_SPONGE)) { - // End the expansion for this column, reached the end - break; + // Do not expand air nor sponge blocks + continue; } - a_Dest.SetBlockTypeMeta(RelX, y, RelZ, BlockType, BlockMeta); - } // for y - } // for x - } // for z + for (int y = Placement.y - 1; y >= 0; y--) + { + BLOCKTYPE ExistingBlock = a_Dest.GetBlockType(RelX, y, RelZ); + if (ExistingBlock != E_BLOCK_AIR) + { + // End the expansion for this column, reached the end + break; + } + a_Dest.SetBlockTypeMeta(RelX, y, RelZ, BlockType, BlockMeta); + } // for y + } // for x + } // for z + } } diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp new file mode 100644 index 000000000..ed9340815 --- /dev/null +++ b/src/Generating/PrefabPiecePool.cpp @@ -0,0 +1,121 @@ + +// PrefabPiecePool.cpp + +// Implements the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces + +#include "Globals.h" +#include "PrefabPiecePool.h" + + + + + +cPrefabPiecePool::cPrefabPiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs +) +{ + AddPieceDefs(a_PieceDefs, a_NumPieceDefs); + if (a_StartingPieceDefs != NULL) + { + AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs); + } +} + + + + + +void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs) +{ + ASSERT(a_PieceDefs != NULL); + for (size_t i = 0; i < a_NumPieceDefs; i++) + { + cPrefab * Prefab = new cPrefab(a_PieceDefs[i]); + m_AllPieces.push_back(Prefab); + AddToPerConnectorMap(Prefab); + } +} + + + + + +void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs) +{ + ASSERT(a_StartingPieceDefs != NULL); + for (size_t i = 0; i < a_NumStartingPieceDefs; i++) + { + cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]); + m_StartingPieces.push_back(Prefab); + } +} + + + + + +void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab) +{ + cPiece::cConnectors Connectors = ((const cPiece *)a_Prefab)->GetConnectors(); + for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) + { + m_PiecesByConnector[itr->m_Type].push_back(a_Prefab); + } +} + + + + +cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType) +{ + return m_PiecesByConnector[a_ConnectorType]; +} + + + + + +cPieces cPrefabPiecePool::GetStartingPieces(void) +{ + if (m_StartingPieces.empty()) + { + return m_AllPieces; + } + else + { + return m_StartingPieces; + } +} + + + + + +int cPrefabPiecePool::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) +{ + return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); +} + + + + + +void cPrefabPiecePool::PiecePlaced(const cPiece & a_Piece) +{ + // Do nothing + UNUSED(a_Piece); +} + + + + + +void cPrefabPiecePool::Reset(void) +{ + // Do nothing +} + + + + diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h new file mode 100644 index 000000000..c6a5ad360 --- /dev/null +++ b/src/Generating/PrefabPiecePool.h @@ -0,0 +1,79 @@ + +// PrefabPiecePool.h + +// Declares the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces + + + + + +#pragma once + +#include "PieceGenerator.h" +#include "Prefab.h" + + + + + +class cPrefabPiecePool : + public cPiecePool +{ +public: + /** Creates an empty instance. Prefabs can be added by calling AddPieceDefs() and AddStartingPieceDefs(). */ + cPrefabPiecePool(void); + + /** Creates a piece pool with prefabs from the specified definitions. + If both a_PieceDefs and a_StartingPieceDefs are given, only the a_StartingPieceDefs are used as starting + pieces for the pool, and they do not participate in the generation any further. + If only a_PieceDefs is given, any such piece can be chosen as a starting piece, and all the pieces are used + for generating. + More pieces can be added to the instance afterwards by calling AddPieceDefs() and AddStartingPieceDefs(). */ + cPrefabPiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs + ); + + /** Adds pieces from the specified definitions into m_AllPieces. Also adds the pieces into + the m_PiecesByConnector map. + May be called multiple times with different PieceDefs, will add all such pieces. */ + void AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs); + + /** Adds pieces from the specified definitions into m_StartingPieces. Doesn't add them to + the m_PiecesByConnector map. + May be called multiple times with different PieceDefs, will add all such pieces. */ + void AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs); + + +protected: + + /** The type used to map a connector type to the list of pieces with that connector */ + typedef std::map<int, cPieces> cPiecesMap; + + /** All the pieces that are allowed for building. + This is the list that's used for memory allocation and deallocation for the pieces. */ + cPieces m_AllPieces; + + /** The pieces that are used as starting pieces. + This list is not shared and the pieces need deallocation. */ + cPieces m_StartingPieces; + + /** The map that has all pieces by their connector types + The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ + cPiecesMap m_PiecesByConnector; + + + /** Adds the prefab to the m_PiecesByConnector map for all its connectors. */ + void AddToPerConnectorMap(cPrefab * a_Prefab); + + // cPiecePool overrides: + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; + virtual cPieces GetStartingPieces(void) override; + virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override; + virtual void PiecePlaced(const cPiece & a_Piece) override; + virtual void Reset(void) override; +} ; + + + + diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp index d2ef5663d..088340391 100644 --- a/src/Generating/Prefabs/NetherFortPrefabs.cpp +++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp @@ -134,7 +134,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 12, 2, 2: 5\n" /* Type 1, direction X+ */ - "1: 0, 2, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 2, 2: 4\n" /* Type 1, direction X- */ + "-1: 12, 2, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 2, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -143,7 +145,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 20, @@ -291,7 +293,10 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 12, 2, 4: 5\n" /* Type 1, direction X+ */ "1: 6, 2, 0: 2\n" /* Type 1, direction Z- */ - "1: 0, 2, 4: 4\n" /* Type 1, direction X- */, + "1: 0, 2, 4: 4\n" /* Type 1, direction X- */ + "-1: 12, 2, 4: 5\n" /* Type -1, direction X+ */ + "-1: 6, 2, 0: 2\n" /* Type -1, direction Z- */ + "-1: 0, 2, 4: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -300,7 +305,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 20, @@ -420,7 +425,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -590,7 +595,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -790,7 +795,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 5, @@ -991,7 +996,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -1085,7 +1090,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -1185,7 +1190,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -1208,7 +1213,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Hitbox (relative to bounding box): 0, 0, 0, // MinX, MinY, MinZ - 4, 6, 15, // MaxX, MaxY, MaxZ + 4, 16, 15, // MaxX, MaxY, MaxZ // Block definitions: ".: 0: 0\n" /* air */ @@ -1364,7 +1369,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -1604,7 +1609,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 5, @@ -1933,7 +1938,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 20, @@ -2052,7 +2057,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 500, @@ -2212,7 +2217,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -2302,7 +2307,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ - "1: 0, 1, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2311,7 +2318,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 300, @@ -2401,7 +2408,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 12, 1, 2: 5\n" /* Type 1, direction X+ */ - "1: 0, 1, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 12, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2410,7 +2419,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 300, @@ -2494,7 +2503,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */ - "1: 0, 1, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2503,7 +2514,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 500, @@ -2631,7 +2642,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */ - "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */, + "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ + "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2640,7 +2653,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -2769,7 +2782,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ - "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */, + "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */ + "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2778,7 +2793,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -2890,7 +2905,11 @@ const cPrefab::sDef g_NetherFortPrefabs[] = "1: 8, 1, 4: 5\n" /* Type 1, direction X+ */ "1: 4, 1, 0: 2\n" /* Type 1, direction Z- */ "1: 4, 1, 8: 3\n" /* Type 1, direction Z+ */ - "1: 0, 1, 4: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 4: 4\n" /* Type 1, direction X- */ + "-1: 8, 1, 4: 5\n" /* Type -1, direction X+ */ + "-1: 4, 1, 8: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */ + "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -2899,7 +2918,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -3040,7 +3059,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ - "1: 8, 8, 2: 5\n" /* Type 1, direction X+ */, + "1: 8, 8, 2: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 8, 8, 2: 5\n" /* Type -1, direction X+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -3049,7 +3070,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 1000, @@ -3139,7 +3160,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ - "1: 13, 1, 2: 5\n" /* Type 1, direction X+ */, + "1: 13, 1, 2: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 13, 1, 2: 5\n" /* Type -1, direction X+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -3148,7 +3171,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -3393,7 +3416,10 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 0, 6, 7: 4\n" /* Type 1, direction X- */ "1: 9, 1, 14: 3\n" /* Type 1, direction Z+ */ - "1: 9, 1, 0: 2\n" /* Type 1, direction Z- */, + "1: 9, 1, 0: 2\n" /* Type 1, direction Z- */ + "-1: 0, 6, 7: 4\n" /* Type -1, direction X- */ + "-1: 9, 1, 14: 3\n" /* Type -1, direction Z+ */ + "-1: 9, 1, 0: 2\n" /* Type -1, direction Z- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -3402,7 +3428,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -3722,7 +3748,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 11, 1, 7: 5\n" /* Type 1, direction X+ */ - "1: 0, 9, 7: 4\n" /* Type 1, direction X- */, + "1: 0, 9, 7: 4\n" /* Type 1, direction X- */ + "-1: 11, 1, 7: 5\n" /* Type -1, direction X+ */ + "-1: 0, 9, 7: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -3731,7 +3759,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -4009,7 +4037,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 10, @@ -4186,7 +4214,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */ - "1: 0, 1, 6: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 6: 4\n" /* Type 1, direction X- */ + "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -4195,7 +4225,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4338,7 +4368,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4481,7 +4511,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4586,7 +4616,10 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 0, 1, 4: 4\n" /* Type 1, direction X- */ "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */ - "1: 12, 1, 4: 5\n" /* Type 1, direction X+ */, + "1: 12, 1, 4: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */ + "-1: 12, 1, 4: 5\n" /* Type -1, direction X+ */ + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -4595,7 +4628,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4712,7 +4745,10 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 0, 1, 6: 4\n" /* Type 1, direction X- */ "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */ - "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */, + "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */ + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */ + "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -4721,7 +4757,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4806,7 +4842,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ - "1: 0, 1, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -4815,7 +4853,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4901,7 +4939,9 @@ const cPrefab::sDef g_NetherFortPrefabs[] = // Connectors: "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ - "1: 0, 1, 2: 4\n" /* Type 1, direction X- */, + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -4910,7 +4950,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -4996,7 +5036,11 @@ const cPrefab::sDef g_NetherFortPrefabs[] = "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */ "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ - "1: 2, 1, 0: 2\n" /* Type 1, direction Z- */, + "1: 2, 1, 0: 2\n" /* Type 1, direction Z- */ + "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -5005,7 +5049,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -5120,7 +5164,7 @@ const cPrefab::sDef g_NetherFortPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, @@ -5314,7 +5358,8 @@ const cPrefab::sDef g_NetherFortStartingPrefabs[] = // Connectors: "0: 6, 1, 0: 2\n" /* Type 0, direction Z- */ - "1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */, + "1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */ + "-1: 6, 1, 12: 3\n" /* Type -1, direction Z+ */, // AllowedRotations: 7, /* 1, 2, 3 CCW rotation allowed */ @@ -5323,7 +5368,7 @@ const cPrefab::sDef g_NetherFortStartingPrefabs[] = cBlockArea::msSpongePrint, // ShouldExtendFloor: - false, + true, // DefaultWeight: 100, diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp index 267dcbbf9..2722e4ca3 100644 --- a/src/Generating/Ravines.cpp +++ b/src/Generating/Ravines.cpp @@ -9,9 +9,6 @@ -/// How many ravines in each direction are generated for a given chunk. Must be an even number -static const int NEIGHBORHOOD_SIZE = 8; - static const int NUM_RAVINE_POINTS = 4; @@ -42,40 +39,38 @@ typedef std::vector<cRavDefPoint> cRavDefPoints; -class cStructGenRavines::cRavine +class cStructGenRavines::cRavine : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + cRavDefPoints m_Points; + - /// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise + /** Generates the shaping defpoints for the ravine, based on the ravine block coords and noise */ void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise); - /// Refines (adds and smooths) defpoints from a_Src into a_Dst + /** Refines (adds and smooths) defpoints from a_Src into a_Dst */ void RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst); - /// Does one round of smoothing, two passes of RefineDefPoints() + /** Does one round of smoothing, two passes of RefineDefPoints() */ void Smooth(void); - /// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block + /** Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block */ void FinishLinear(void); public: - // Coords for which the ravine was generated (not necessarily the center) - int m_BlockX; - int m_BlockZ; cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise); - /// Carves the ravine into the chunk specified - void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap - ); - #ifdef _DEBUG /// Exports itself as a SVG line definition AString ExportAsSVG(int a_Color, int a_OffsetX = 0, int a_OffsetZ = 0) const; #endif // _DEBUG + +protected: + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override; } ; @@ -86,6 +81,7 @@ public: // cStructGenRavines: cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) : + super(a_Seed, a_Size, a_Size, a_Size * 2, a_Size * 2, 100), m_Noise(a_Seed), m_Size(a_Size) { @@ -95,139 +91,9 @@ cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) : -cStructGenRavines::~cStructGenRavines() -{ - ClearCache(); -} - - - - - -void cStructGenRavines::ClearCache(void) +cGridStructGen::cStructurePtr cStructGenRavines::CreateStructure(int a_OriginX, int a_OriginZ) { - for (cRavines::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cRavines Ravines; - GetRavinesForChunk(ChunkX, ChunkZ, Ravines); - for (cRavines::const_iterator itr = Ravines.begin(), end = Ravines.end(); itr != end; ++itr) - { - (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - } // for itr - Ravines[] -} - - - - - -void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenRavines::cRavines & a_Ravines) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_Size; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_Size; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= 4; - BaseZ -= 4; - - // Walk the cache, move each ravine that we want into a_Ravines: - int StartX = BaseX * m_Size; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Size; - int StartZ = BaseZ * m_Size; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Size; - for (cRavines::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_Ravines.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_Size; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_Size; - bool Found = false; - for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } - if (!Found) - { - a_Ravines.push_back(new cRavine(RealX, RealZ, m_Size, m_Noise)); - } - } - } - - // Copy a_Ravines into m_Cache to the beginning: - cRavines RavinesCopy(a_Ravines); - m_Cache.splice(m_Cache.begin(), RavinesCopy, RavinesCopy.begin(), RavinesCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cRavines::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cRavines::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } - - /* - #ifdef _DEBUG - // DEBUG: Export as SVG into a file specific for the chunk, for visual verification: - AString SVG; - SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n"); - for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr) - { - SVG.append((*itr)->ExportAsSVG(0, 512, 512)); - } - SVG.append("</svg>\n"); - - AString fnam; - Printf(fnam, "ravines\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); - cFile File(fnam, cFile::fmWrite); - File.Write(SVG.c_str(), SVG.size()); - #endif // _DEBUG - //*/ + return cStructurePtr(new cRavine(a_OriginX, a_OriginZ, m_Size, m_Noise)); } @@ -238,14 +104,13 @@ void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGe /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenRavines::cRavine -cStructGenRavines::cRavine::cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ) +cStructGenRavines::cRavine::cRavine(int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise) : + super(a_OriginX, a_OriginZ) { // Calculate the ravine shape-defining points: - GenerateBaseDefPoints(a_BlockX, a_BlockZ, a_Size, a_Noise); + GenerateBaseDefPoints(a_OriginX, a_OriginZ, a_Size, a_Noise); - // Smooth the ravine. A two passes are needed: + // Smooth the ravine. Two passes are needed: Smooth(); Smooth(); @@ -263,8 +128,8 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block a_Size = (512 + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 11 * a_BlockZ, a_BlockX + a_BlockZ) / 17) % 512)) * a_Size / 1024; // The complete offset of the ravine from its cellpoint, up to 2 * a_Size in each direction - int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2; - int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2; + int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2; + int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2; int CenterX = a_BlockX + OffsetX; int CenterZ = a_BlockZ + OffsetZ; @@ -306,8 +171,14 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst) { + if (a_Src.size() < 2) + { + // No midpoints, nothing to refine + return; + } + // Smoothing: for each line segment, add points on its 1/4 lengths - int Num = a_Src.size() - 2; // this many intermediary points + size_t Num = a_Src.size() - 2; // this many intermediary points a_Dst.clear(); a_Dst.reserve(Num * 2 + 2); cRavDefPoints::const_iterator itr = a_Src.begin() + 1; @@ -318,7 +189,7 @@ void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cR int PrevR = Source.m_Radius; int PrevT = Source.m_Top; int PrevB = Source.m_Bottom; - for (int i = 0; i <= Num; ++i, ++itr) + for (size_t i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; int dz = itr->m_BlockZ - PrevZ; @@ -423,15 +294,15 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int // Base point highlight: AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ + a_OffsetX + m_OriginX - 5, a_OffsetZ + m_OriginZ, a_OffsetX + m_OriginX + 5, a_OffsetZ + m_OriginZ ); AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 + a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ - 5, a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ + 5 ); // A gray line from the base point to the first point of the ravine, for identification: AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ + a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ ); // Offset guides: @@ -455,14 +326,10 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int -void cStructGenRavines::cRavine::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap -) +void cStructGenRavines::cRavine::DrawIntoChunk(cChunkDesc & a_ChunkDesc) { - int BlockStartX = a_ChunkX * cChunkDef::Width; - int BlockStartZ = a_ChunkZ * cChunkDef::Width; + int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; int BlockEndX = BlockStartX + cChunkDef::Width; int BlockEndZ = BlockStartZ + cChunkDef::Width; for (cRavDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr) @@ -488,7 +355,7 @@ void cStructGenRavines::cRavine::ProcessChunk( // DEBUG: Make the ravine shapepoints visible on a single layer (so that we can see with Minutor what's going on) if ((DifX + x == 0) && (DifZ + z == 0)) { - cChunkDef::SetBlock(a_BlockTypes, x, 4, z, E_BLOCK_LAPIS_ORE); + a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE); } #endif // _DEBUG @@ -498,7 +365,7 @@ void cStructGenRavines::cRavine::ProcessChunk( int Top = std::min(itr->m_Top, (int)(cChunkDef::Height)); // Stupid gcc needs int cast for (int y = std::max(itr->m_Bottom, 1); y <= Top; y++) { - switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z)) + switch (a_ChunkDesc.GetBlockType(x, y, z)) { // Only carve out these specific block types case E_BLOCK_DIRT: @@ -516,7 +383,7 @@ void cStructGenRavines::cRavine::ProcessChunk( case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: { - cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); break; } default: break; diff --git a/src/Generating/Ravines.h b/src/Generating/Ravines.h index c76b9f19f..30b47e9ec 100644 --- a/src/Generating/Ravines.h +++ b/src/Generating/Ravines.h @@ -9,7 +9,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -17,28 +17,22 @@ class cStructGenRavines : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; + public: cStructGenRavines(int a_Seed, int a_Size); - ~cStructGenRavines(); protected: class cRavine; // fwd: Ravines.cpp - typedef std::list<cRavine *> cRavines; - - cNoise m_Noise; - int m_Size; // Max size, in blocks, of the ravines generated - cRavines m_Cache; - /// Clears everything from the cache - void ClearCache(void); + cNoise m_Noise; + int m_Size; // Max size, in blocks, of the ravines generated - /// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function. - void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines); - - // cFinishGen override: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 4909587b1..4f1553c36 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -136,7 +136,7 @@ inline void PushSomeColumns(int a_BlockX, int a_Height, int a_BlockZ, int a_Colu { int x = a_BlockX + a_Coords[i].x; int z = a_BlockZ + a_Coords[i].z; - if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + i, z + 64 * a_Seq) <= a_Chance) + if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + (int)i, z + 64 * a_Seq) <= a_Chance) { for (int j = 0; j < a_ColumnHeight; j++) { diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 33b601e82..3586560bf 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -79,23 +79,24 @@ void cGroupManager::CheckUsers(void) return; } - unsigned int NumKeys = IniFile.GetNumKeys(); - for (size_t i = 0; i < NumKeys; i++) + int NumKeys = IniFile.GetNumKeys(); + for (int i = 0; i < NumKeys; i++) { - AString Player = IniFile.GetKeyName( i ); + AString Player = IniFile.GetKeyName(i); AString Groups = IniFile.GetValue(Player, "Groups", ""); - if (!Groups.empty()) + if (Groups.empty()) + { + continue; + } + AStringVector Split = StringSplitAndTrim(Groups, ","); + for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) { - AStringVector Split = StringSplit( Groups, "," ); - for( unsigned int i = 0; i < Split.size(); i++ ) + if (!ExistsGroup(*itr)) { - if (!ExistsGroup(Split[i])) - { - LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str()); - } + LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str()); } - } - } + } // for itr - Split[] + } // for i - ini file keys } @@ -128,15 +129,15 @@ void cGroupManager::LoadGroups() IniFile.WriteFile("groups.ini"); } - unsigned int NumKeys = IniFile.GetNumKeys(); - for (size_t i = 0; i < NumKeys; i++) + int NumKeys = IniFile.GetNumKeys(); + for (int i = 0; i < NumKeys; i++) { - AString KeyName = IniFile.GetKeyName( i ); - cGroup* Group = GetGroup( KeyName.c_str() ); + AString KeyName = IniFile.GetKeyName(i); + cGroup * Group = GetGroup(KeyName.c_str()); Group->ClearPermission(); // Needed in case the groups are reloaded. - LOGD("Loading group: %s", KeyName.c_str() ); + LOGD("Loading group %s", KeyName.c_str()); Group->SetName(KeyName); AString Color = IniFile.GetValue(KeyName, "Color", "-"); diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp index 3f6c17dda..f16ea1915 100644 --- a/src/HTTPServer/NameValueParser.cpp +++ b/src/HTTPServer/NameValueParser.cpp @@ -97,7 +97,7 @@ void cNameValueParser::Parse(const char * a_Data, size_t a_Size) { ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong! - int Last = 0; + size_t Last = 0; for (size_t i = 0; i < a_Size;) { switch (m_State) diff --git a/src/Inventory.cpp b/src/Inventory.cpp index c7c089d5f..a365e4ed4 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -376,6 +376,7 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount) if (!Grid->DamageItem(GridSlotNum, a_Amount)) { // The item has been damaged, but did not break yet + SendSlot(a_SlotNum); return false; } diff --git a/src/Item.cpp b/src/Item.cpp index 7e472f6d8..d6e8b224a 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -151,6 +151,8 @@ void cItem::GetJson(Json::Value & a_OutValue) const a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem); a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem); } + + a_OutValue["RepairCost"] = m_RepairCost; } } @@ -179,6 +181,8 @@ void cItem::FromJson(const Json::Value & a_Value) m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem); m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem); } + + m_RepairCost = a_Value.get("RepairCost", 0).asInt(); } } diff --git a/src/Item.h b/src/Item.h index 8eb0a1f4e..2f65d5344 100644 --- a/src/Item.h +++ b/src/Item.h @@ -40,6 +40,7 @@ public: m_ItemDamage(0), m_CustomName(""), m_Lore(""), + m_RepairCost(0), m_FireworkItem() { } @@ -60,6 +61,7 @@ public: m_Enchantments(a_Enchantments), m_CustomName (a_CustomName), m_Lore (a_Lore), + m_RepairCost (0), m_FireworkItem() { if (!IsValidItem(m_ItemType)) @@ -85,6 +87,7 @@ public: m_Enchantments(a_CopyFrom.m_Enchantments), m_CustomName (a_CopyFrom.m_CustomName), m_Lore (a_CopyFrom.m_Lore), + m_RepairCost (a_CopyFrom.m_RepairCost), m_FireworkItem(a_CopyFrom.m_FireworkItem) { } @@ -100,6 +103,7 @@ public: m_Enchantments.Clear(); m_CustomName = ""; m_Lore = ""; + m_RepairCost = 0; m_FireworkItem.EmptyData(); } @@ -109,6 +113,7 @@ public: m_ItemType = E_ITEM_EMPTY; m_ItemCount = 0; m_ItemDamage = 0; + m_RepairCost = 0; } @@ -190,14 +195,15 @@ public: // tolua_begin - short m_ItemType; - char m_ItemCount; - short m_ItemDamage; - cEnchantments m_Enchantments; - AString m_CustomName; - AString m_Lore; - - cFireworkItem m_FireworkItem; + short m_ItemType; + char m_ItemCount; + short m_ItemDamage; + cEnchantments m_Enchantments; + AString m_CustomName; + AString m_Lore; + + int m_RepairCost; + cFireworkItem m_FireworkItem; }; // tolua_end diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h index 08cddb1ad..2436df5bd 100644 --- a/src/Items/ItemArmor.h +++ b/src/Items/ItemArmor.h @@ -60,6 +60,49 @@ public: return true; } + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_CHAIN_BOOTS: + case E_ITEM_CHAIN_CHESTPLATE: + case E_ITEM_CHAIN_HELMET: + case E_ITEM_CHAIN_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_DIAMOND_BOOTS: + case E_ITEM_DIAMOND_CHESTPLATE: + case E_ITEM_DIAMOND_HELMET: + case E_ITEM_DIAMOND_LEGGINGS: + { + return (a_ItemType == E_ITEM_DIAMOND); + } + case E_ITEM_IRON_BOOTS: + case E_ITEM_IRON_CHESTPLATE: + case E_ITEM_IRON_HELMET: + case E_ITEM_IRON_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_GOLD_BOOTS: + case E_ITEM_GOLD_CHESTPLATE: + case E_ITEM_GOLD_HELMET: + case E_ITEM_GOLD_LEGGINGS: + { + return (a_ItemType == E_ITEM_GOLD); + } + case E_ITEM_LEATHER_BOOTS: + case E_ITEM_LEATHER_CAP: + case E_ITEM_LEATHER_PANTS: + case E_ITEM_LEATHER_TUNIC: + { + return (a_ItemType == E_ITEM_LEATHER); + } + } + return false; + } + } ; diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index ce9593a70..d97f986ba 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -511,6 +511,16 @@ bool cItemHandler::IsPlaceable(void) + +bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType) +{ + return false; +} + + + + + bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) { UNUSED(a_BlockType); diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 4993eac85..e13198cd7 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -85,6 +85,9 @@ public: /** Blocks simply get placed */ virtual bool IsPlaceable(void); + /** Can the anvil repair this item, when a_Item is the second input? */ + virtual bool CanRepairWithRawMaterial(short a_ItemType); + /** Called before a block is placed into a world. The handler should return true to allow placement, false to refuse. Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h index 8fc1d8543..bc650cdbd 100644 --- a/src/Items/ItemLilypad.h +++ b/src/Items/ItemLilypad.h @@ -47,9 +47,9 @@ public: public cBlockTracer::cCallbacks { public: - cCallbacks(cWorld * a_CBWorld) : - m_HasHitFluid(false), - m_World(a_CBWorld) + + cCallbacks(void) : + m_HasHitFluid(false) { } @@ -62,10 +62,9 @@ public: return false; } AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, BLOCK_FACE_YP); // Always place pad at top of water block - BLOCKTYPE Block = m_World->GetBlock(a_CBBlockX, a_CBBlockY, a_CBBlockZ); if ( - !IsBlockWater(Block) && - cBlockInfo::FullyOccupiesVoxel(Block) + !IsBlockWater(a_CBBlockType) && + cBlockInfo::FullyOccupiesVoxel(a_CBBlockType) ) { // Can't place lilypad on air/in another block! @@ -80,11 +79,10 @@ public: Vector3i m_Pos; bool m_HasHitFluid; - cWorld * m_World; }; - cCallbacks Callbacks(a_World); + cCallbacks Callbacks; cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks); Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 25500aeb9..4e7d8fcff 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -78,7 +78,7 @@ public: } return true; } - + } ; diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h index 2a8e40daa..82bec52d4 100644 --- a/src/Items/ItemPickaxe.h +++ b/src/Items/ItemPickaxe.h @@ -76,6 +76,7 @@ public: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_BRICK: case E_BLOCK_COBBLESTONE_STAIRS: + case E_BLOCK_COBBLESTONE_WALL: case E_BLOCK_STONE_BRICK_STAIRS: case E_BLOCK_NETHER_BRICK_STAIRS: case E_BLOCK_CAULDRON: @@ -85,6 +86,19 @@ public: } return false; } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_PICKAXE: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_PICKAXE: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_PICKAXE: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_PICKAXE: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_PICKAXE: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } } ; diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h index 873d5ae25..333ba46e8 100644 --- a/src/Items/ItemShovel.h +++ b/src/Items/ItemShovel.h @@ -41,4 +41,18 @@ public: { return (a_BlockType == E_BLOCK_SNOW); } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SHOVEL: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SHOVEL: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SHOVEL: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SHOVEL: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SHOVEL: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } + }; diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index 0d6019398..bba97afa1 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -33,7 +33,10 @@ public: a_BlockY--; } - if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0) + cMonster::eType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); + if ( + (MonsterType != cMonster::mtInvalidType) && // Valid monster type + (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { @@ -45,6 +48,41 @@ public: return false; } + + + /** Converts the Spawn egg item damage to the monster type to spawn. + Returns mtInvalidType for invalid damage values. */ + static cMonster::eType ItemDamageToMonsterType(short a_ItemDamage) + { + switch (a_ItemDamage) + { + case E_META_SPAWN_EGG_BAT: return cMonster::mtBat; + case E_META_SPAWN_EGG_BLAZE: return cMonster::mtBlaze; + case E_META_SPAWN_EGG_CAVE_SPIDER: return cMonster::mtCaveSpider; + case E_META_SPAWN_EGG_CHICKEN: return cMonster::mtChicken; + case E_META_SPAWN_EGG_COW: return cMonster::mtCow; + case E_META_SPAWN_EGG_CREEPER: return cMonster::mtCreeper; + case E_META_SPAWN_EGG_ENDERMAN: return cMonster::mtEnderman; + case E_META_SPAWN_EGG_GHAST: return cMonster::mtGhast; + case E_META_SPAWN_EGG_HORSE: return cMonster::mtHorse; + case E_META_SPAWN_EGG_MAGMA_CUBE: return cMonster::mtMagmaCube; + case E_META_SPAWN_EGG_MOOSHROOM: return cMonster::mtMooshroom; + case E_META_SPAWN_EGG_OCELOT: return cMonster::mtOcelot; + case E_META_SPAWN_EGG_PIG: return cMonster::mtPig; + case E_META_SPAWN_EGG_SHEEP: return cMonster::mtSheep; + case E_META_SPAWN_EGG_SILVERFISH: return cMonster::mtSilverfish; + case E_META_SPAWN_EGG_SKELETON: return cMonster::mtSkeleton; + case E_META_SPAWN_EGG_SLIME: return cMonster::mtSlime; + case E_META_SPAWN_EGG_SPIDER: return cMonster::mtSpider; + case E_META_SPAWN_EGG_SQUID: return cMonster::mtSquid; + case E_META_SPAWN_EGG_VILLAGER: return cMonster::mtVillager; + case E_META_SPAWN_EGG_WITCH: return cMonster::mtWitch; + case E_META_SPAWN_EGG_WOLF: return cMonster::mtWolf; + case E_META_SPAWN_EGG_ZOMBIE: return cMonster::mtZombie; + case E_META_SPAWN_EGG_ZOMBIE_PIGMAN: return cMonster::mtZombiePigman; + } + return cMonster::mtInvalidType; + } } ; diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h index a7c1d2432..44feb2d83 100644 --- a/src/Items/ItemSword.h +++ b/src/Items/ItemSword.h @@ -23,6 +23,19 @@ public: { return (a_BlockType == E_BLOCK_COBWEB); } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SWORD: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SWORD: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SWORD: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SWORD: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SWORD: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } } ; diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index c6a4e714e..35c2b8731 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -28,15 +28,19 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; + + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0) + { + return false; + } + if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); } - Vector3d Pos = a_Player->GetThrowStartPos(); - Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; - a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed); - return true; } @@ -127,7 +131,10 @@ public: return false; } - a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()); + if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0) + { + return false; + } if (!a_Player->IsGameModeCreative()) { diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index 5ba2940d2..5459644af 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -106,11 +106,13 @@ void cLightingThread::Stop(void) cCSLock Lock(m_CS); for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr) { + (*itr)->Disable(); delete *itr; } m_PendingQueue.clear(); for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr) { + (*itr)->Disable(); delete *itr; } m_Queue.clear(); diff --git a/src/Map.cpp b/src/Map.cpp index 79370b097..7721baa70 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -614,7 +614,7 @@ unsigned int cMap::GetNumPixels(void) const -unsigned int cMap::GetNumDecorators(void) const +size_t cMap::GetNumDecorators(void) const { return m_Decorators.size(); } @@ -181,7 +181,7 @@ public: // tolua_end - unsigned int GetNumDecorators(void) const; + size_t GetNumDecorators(void) const; const cColorList & GetData(void) const { return m_Data; } diff --git a/src/MapManager.cpp b/src/MapManager.cpp index 9d02eafb4..e7df75118 100644 --- a/src/MapManager.cpp +++ b/src/MapManager.cpp @@ -86,7 +86,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale) return NULL; } - cMap Map(m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale); + cMap Map((unsigned)m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale); m_MapData.push_back(Map); @@ -97,7 +97,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale) -unsigned int cMapManager::GetNumMaps(void) const +size_t cMapManager::GetNumMaps(void) const { return m_MapData.size(); } @@ -151,7 +151,7 @@ void cMapManager::SaveMapData(void) cIDCountSerializer IDSerializer(m_World->GetName()); - IDSerializer.SetMapCount(m_MapData.size()); + IDSerializer.SetMapCount((unsigned)m_MapData.size()); if (!IDSerializer.Save()) { diff --git a/src/MapManager.h b/src/MapManager.h index 80e6d16d1..ceab8f126 100644 --- a/src/MapManager.h +++ b/src/MapManager.h @@ -53,7 +53,7 @@ public: */ bool ForEachMap(cMapCallback & a_Callback); - unsigned int GetNumMaps(void) const; // tolua_export + size_t GetNumMaps(void) const; // tolua_export /** Loads the map data from the disk */ void LoadMapData(void); diff --git a/src/MobCensus.cpp b/src/MobCensus.cpp index 9c32bf695..23f74b59e 100644 --- a/src/MobCensus.cpp +++ b/src/MobCensus.cpp @@ -64,7 +64,7 @@ void cMobCensus::CollectSpawnableChunk(cChunk & a_Chunk) int cMobCensus::GetNumChunks(void) { - return m_EligibleForSpawnChunks.size(); + return (int)m_EligibleForSpawnChunks.size(); } diff --git a/src/MobFamilyCollecter.cpp b/src/MobFamilyCollecter.cpp index e9c69e078..6da330c83 100644 --- a/src/MobFamilyCollecter.cpp +++ b/src/MobFamilyCollecter.cpp @@ -18,7 +18,7 @@ void cMobFamilyCollecter::CollectMob(cMonster & a_Monster) int cMobFamilyCollecter::GetNumberOfCollectedMobs(cMonster::eFamily a_Family) { - return m_Mobs[a_Family].size(); + return (int)m_Mobs[a_Family].size(); } diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index ce8e06777..de8e01b8a 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -104,13 +104,13 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) } } - int allowedMobsSize = allowedMobs.size(); + size_t allowedMobsSize = allowedMobs.size(); if (allowedMobsSize > 0) { std::set<cMonster::eType>::iterator itr = allowedMobs.begin(); - int iRandom = m_Random.NextInt(allowedMobsSize,a_Biome); + int iRandom = m_Random.NextInt((int)allowedMobsSize, a_Biome); - for(int i = 0; i < iRandom; i++) + for (int i = 0; i < iRandom; i++) { ++itr; } diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 447bf3549..85b122034 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -108,14 +108,13 @@ void cAggressiveMonster::Attack(float a_Dt) bool cAggressiveMonster::IsMovingToTargetPosition() { - static const float epsilon = 0.000000000001f; // Difference between destination x and target x is negligible (to 10^-12 precision) - if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < epsilon) + if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon()) { return false; } // Difference between destination z and target z is negligible (to 10^-12 precision) - else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > epsilon) + else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon()) { return false; } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index c66ab4e04..62670907f 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -827,6 +827,10 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) switch (a_MobType) { case mtMagmaCube: + { + toReturn = new cMagmaCube(Random.NextInt(2) + 1); + break; + } case mtSlime: { toReturn = new cSlime(Random.NextInt(2) + 1); diff --git a/src/Noise.cpp b/src/Noise.cpp index 13a194938..89115d992 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -814,7 +814,7 @@ void cPerlinNoise::SetSeed(int a_Seed) void cPerlinNoise::AddOctave(float a_Frequency, float a_Amplitude) { - m_Octaves.push_back(cOctave(m_Seed * (m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude)); + m_Octaves.push_back(cOctave(m_Seed * ((int)m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude)); } diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 33b9cfc3f..8c24fa541 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -75,7 +75,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) } #ifdef _WIN32 - fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode); + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR); #else m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode); #endif // _WIN32 @@ -88,7 +88,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) // Simply re-open for read-writing, erasing existing contents: #ifdef _WIN32 - fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), "wb+"); + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR); #else m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+"); #endif // _WIN32 diff --git a/src/OSSupport/ListenThread.cpp b/src/OSSupport/ListenThread.cpp index ba3198764..02e98acfc 100644 --- a/src/OSSupport/ListenThread.cpp +++ b/src/OSSupport/ListenThread.cpp @@ -214,7 +214,7 @@ void cListenThread::Execute(void) timeval tv; // On Linux select() doesn't seem to wake up when socket is closed, so let's kinda busy-wait: tv.tv_sec = 1; tv.tv_usec = 0; - if (select(Highest + 1, &fdRead, NULL, NULL, &tv) == -1) + if (select((int)Highest + 1, &fdRead, NULL, NULL, &tv) == -1) { LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index 98f694a79..56835b518 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -328,18 +328,18 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por -int cSocket::Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags) +int cSocket::Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags) { - return recv(m_Socket, a_Buffer, a_Length, a_Flags); + return recv(m_Socket, a_Buffer, (int)a_Length, a_Flags); } -int cSocket::Send(const char * a_Buffer, unsigned int a_Length) +int cSocket::Send(const char * a_Buffer, size_t a_Length) { - return send(m_Socket, a_Buffer, a_Length, MSG_NOSIGNAL); + return send(m_Socket, a_Buffer, (int)a_Length, MSG_NOSIGNAL); } diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h index bdc2babf5..35ecadfa0 100644 --- a/src/OSSupport/Socket.h +++ b/src/OSSupport/Socket.h @@ -110,8 +110,8 @@ public: /// Connects to the specified host or string IP address and port, using IPv4. Returns true if successful. bool ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port); - int Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags); - int Send (const char * a_Buffer, unsigned int a_Length); + int Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags); + int Send (const char * a_Buffer, size_t a_Length); unsigned short GetPort(void) const; // Returns 0 on failure diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index 0bc1d6b55..0ab5b6298 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -406,7 +406,7 @@ void cSocketThreads::cSocketThread::Execute(void) timeval Timeout; Timeout.tv_sec = 5; Timeout.tv_usec = 0; - if (select(Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1) + if (select((int)Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1) { LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; diff --git a/src/ProbabDistrib.cpp b/src/ProbabDistrib.cpp index 5fa17c276..7a5869dcc 100644 --- a/src/ProbabDistrib.cpp +++ b/src/ProbabDistrib.cpp @@ -118,7 +118,7 @@ int cProbabDistrib::MapValue(int a_OrigValue) const size_t Hi = m_Cumulative.size() - 1; while (Hi - Lo > 1) { - int Mid = (Lo + Hi) / 2; + size_t Mid = (Lo + Hi) / 2; int MidProbab = m_Cumulative[Mid].m_Probability; if (MidProbab < a_OrigValue) { diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 41d614e58..2050393c2 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -214,7 +214,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S ReplaceString(ActualAddress, "%SERVERID%", a_ServerId); AString Request; - Request += "GET " + ActualAddress + " HTTP/1.1\r\n"; + Request += "GET " + ActualAddress + " HTTP/1.0\r\n"; Request += "Host: " + m_Server + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index bc9aff0c0..443723e40 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -197,7 +197,7 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkZ); Pkt.WriteShort((short)a_Changes.size()); - Pkt.WriteInt(a_Changes.size() * 4); + Pkt.WriteInt((int)a_Changes.size() * 4); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); @@ -532,7 +532,7 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc Pkt.WriteFloat((float)a_BlockY); Pkt.WriteFloat((float)a_BlockZ); Pkt.WriteFloat((float)a_Radius); - Pkt.WriteInt(a_BlocksAffected.size()); + Pkt.WriteInt((int)a_BlocksAffected.size()); for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) { Pkt.WriteChar((char)itr->x); @@ -698,7 +698,7 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor cPacketizer Pkt(*this, 0x34); Pkt.WriteVarInt(a_ID); - Pkt.WriteShort (1 + (3 * a_Decorators.size())); + Pkt.WriteShort ((short)(1 + (3 * a_Decorators.size()))); Pkt.WriteByte(1); @@ -1174,7 +1174,7 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results) ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet - Pkt.WriteVarInt(a_Results.size()); + Pkt.WriteVarInt((int)a_Results.size()); for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) { @@ -1743,7 +1743,7 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) cPacketizer Pkt(*this, 0x01); Pkt.WriteString(Server->GetServerID()); const AString & PubKeyDer = Server->GetPublicKeyDER(); - Pkt.WriteShort(PubKeyDer.size()); + Pkt.WriteShort((short)PubKeyDer.size()); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); Pkt.WriteShort(4); Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) @@ -2138,7 +2138,7 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet) cCSLock Lock(m_CSPacket); AString Pkt; a_Packet.ReadAll(Pkt); - WriteVarInt(Pkt.size()); + WriteVarInt((UInt32)Pkt.size()); SendData(Pkt.data(), Pkt.size()); Flush(); } @@ -2278,6 +2278,13 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) } break; } + case TAG_Int: + { + if (TagName == "RepairCost") + { + a_Item.m_RepairCost = NBT.GetInt(tag); + } + } default: LOGD("Unimplemented NBT data when parsing!"); break; } } @@ -2396,7 +2403,7 @@ cProtocol172::cPacketizer::~cPacketizer() AString DataToSend; // Send the packet length - UInt32 PacketLen = m_Out.GetUsedSpace(); + UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace(); m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen); m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend); m_Protocol.SendData(DataToSend.data(), DataToSend.size()); @@ -2451,6 +2458,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) // Send the enchantments and custom names: cFastNBTWriter Writer; + if (a_Item.m_RepairCost != 0) + { + Writer.AddInt("RepairCost", a_Item.m_RepairCost); + } if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; @@ -2489,7 +2500,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } @@ -2559,7 +2570,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index eed761a4a..dc111e737 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -238,7 +238,7 @@ protected: bool m_IsEncrypted; cAesCfb128Decryptor m_Decryptor; - cAesCfb128Decryptor m_Encryptor; + cAesCfb128Encryptor m_Encryptor; /** The logfile where the comm is logged, when g_ShouldLogComm is true */ cFile m_CommLogFile; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 22dfe7c88..667fb5cef 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -871,7 +871,7 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) // Not enough bytes for the packet length, keep waiting return false; } - ReadSoFar -= m_Buffer.GetReadableSpace(); + ReadSoFar -= (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.CanReadBytes(PacketLen)) { // Not enough bytes for the packet, keep waiting @@ -961,7 +961,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema { return false; } - NumBytesRead -= m_Buffer.GetReadableSpace(); + NumBytesRead -= (UInt32)m_Buffer.GetReadableSpace(); switch (ProtocolVersion) { case PROTO_VERSION_1_7_2: diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index cd5292ac3..c511968be 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -59,7 +59,7 @@ public: virtual void Finished(void) override { - m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, m_Buffer.size(), m_Buffer.c_str()); + m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, (int)m_Buffer.size(), m_Buffer.c_str()); delete this; } diff --git a/src/Root.cpp b/src/Root.cpp index 5d32bdd87..c82b05a66 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -590,13 +590,13 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac { class cCallback : public cPlayerListCallback { - unsigned m_BestRating; - unsigned m_NameLength; + size_t m_BestRating; + size_t m_NameLength; const AString m_PlayerName; virtual bool Item (cPlayer * a_pPlayer) { - unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName()); + size_t Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName()); if ((Rating > 0) && (Rating >= m_BestRating)) { m_BestMatch = a_pPlayer; @@ -626,7 +626,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac cPlayer * m_BestMatch; unsigned m_NumMatches; } Callback (a_PlayerName); - ForEachPlayer( Callback ); + ForEachPlayer(Callback); if (Callback.m_NumMatches == 1) { @@ -763,8 +763,8 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) { cWorld * World = itr->second; int NumInGenerator = World->GetGeneratorQueueLength(); - int NumInSaveQueue = World->GetStorageSaveQueueLength(); - int NumInLoadQueue = World->GetStorageLoadQueueLength(); + int NumInSaveQueue = (int)World->GetStorageSaveQueueLength(); + int NumInLoadQueue = (int)World->GetStorageLoadQueueLength(); int NumValid = 0; int NumDirty = 0; int NumInLighting = 0; @@ -784,8 +784,6 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) a_Output.Out(" block lighting: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024); a_Output.Out(" heightmap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024); a_Output.Out(" biomemap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024); - int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap); - a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024); SumNumValid += NumValid; SumNumDirty += NumDirty; SumNumInLighting += NumInLighting; diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 4c89ce265..250f63aa9 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -261,7 +261,7 @@ void cTeam::SetDisplayName(const AString & a_Name) -unsigned int cTeam::GetNumPlayers(void) const +size_t cTeam::GetNumPlayers(void) const { return m_Players.size(); } @@ -569,7 +569,7 @@ void cScoreboard::SendTo(cClientHandle & a_Client) -unsigned int cScoreboard::GetNumObjectives(void) const +size_t cScoreboard::GetNumObjectives(void) const { return m_Objectives.size(); } @@ -578,7 +578,7 @@ unsigned int cScoreboard::GetNumObjectives(void) const -unsigned int cScoreboard::GetNumTeams(void) const +size_t cScoreboard::GetNumTeams(void) const { return m_Teams.size(); } diff --git a/src/Scoreboard.h b/src/Scoreboard.h index 2fae5e499..1e1973a10 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -153,7 +153,7 @@ public: // tolua_begin /** Returns the number of registered players */ - unsigned int GetNumPlayers(void) const; + size_t GetNumPlayers(void) const; bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; } bool CanSeeFriendlyInvisible(void) const { return m_CanSeeFriendlyInvisible; } @@ -248,9 +248,9 @@ public: cObjective * GetObjectiveIn(eDisplaySlot a_Slot); - unsigned int GetNumObjectives(void) const; + size_t GetNumObjectives(void) const; - unsigned int GetNumTeams(void) const; + size_t GetNumTeams(void) const; void AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value = 1); diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index bc5158d95..5ff736231 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -148,7 +148,7 @@ void cDelayedFluidSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_Chunk { SimulateBlock(a_Chunk, itr->x, itr->y, itr->z); } - m_TotalBlocks -= Blocks.size(); + m_TotalBlocks -= (int)Blocks.size(); Blocks.clear(); } } diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 03e94e791..e95af3a1c 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -119,7 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re if (SpreadFurther && (NewMeta < 8)) { // Spread to the neighbors: - Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); + SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); } // Mark as processed: @@ -130,7 +130,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re -void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) +void cFloodyFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) { SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta); SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta); diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h index 632de3bb2..8e1be5e6b 100644 --- a/src/Simulator/FloodyFluidSimulator.h +++ b/src/Simulator/FloodyFluidSimulator.h @@ -48,16 +48,13 @@ protected: bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); /** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block. - * - * Returns whether the block was changed or not. - */ + Returns whether the block was changed or not. */ bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta); - /** Spread water to neighbors. - * - * May be overridden to provide more sophisticated algorithms. - */ - virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta); + /** Spread fluid to XZ neighbors. + The coords are of the block currently being processed; a_NewMeta is the new meta for the new fluid block. + Descendants may overridde to provide more sophisticated algorithms. */ + virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta); } ; diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index d37d2eecf..074063add 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -9,6 +9,8 @@ #include "../Entities/Pickup.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" +#include "../Blocks/BlockButton.h" +#include "../Blocks/BlockLever.h" #include "../Piston.h" @@ -116,7 +118,9 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, // Things that can send power through a block but which depends on meta ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || - (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) + (((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)) ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); @@ -139,14 +143,14 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, SimulatedPlayerToggleableList * SimulatedPlayerToggleableBlocks = a_Chunk->GetRedstoneSimulatorSimulatedPlayerToggleableList(); for (SimulatedPlayerToggleableList::iterator itr = SimulatedPlayerToggleableBlocks->begin(); itr != SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ))) { continue; } if (!IsAllowedBlock(Block)) { - LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z); SimulatedPlayerToggleableBlocks->erase(itr); break; } @@ -155,7 +159,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, RepeatersDelayList * RepeatersDelayList = a_Chunk->GetRedstoneSimulatorRepeatersDelayList(); for (RepeatersDelayList::iterator itr = RepeatersDelayList->begin(); itr != RepeatersDelayList->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ))) { continue; } @@ -221,9 +225,6 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int m_LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); m_Chunk = a_Chunk; - int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - for (cRedstoneSimulatorChunkData::iterator dataitr = m_RedstoneSimulatorChunkData->begin(); dataitr != m_RedstoneSimulatorChunkData->end();) { if (dataitr->DataTwo) @@ -232,67 +233,65 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int continue; } - int a_X = BaseX + dataitr->x; - int a_Z = BaseZ + dataitr->z; switch (dataitr->Data) { - case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; - case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; - case E_BLOCK_FENCE_GATE: HandleFenceGate(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; - case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; - case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break; - case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break; - case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break; + case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: { - HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneTorch(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_STONE_BUTTON: case E_BLOCK_WOODEN_BUTTON: { - HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_ON: { - HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: { - HandlePiston(a_X, dataitr->y, a_Z); + HandlePiston(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_REDSTONE_LAMP_OFF: case E_BLOCK_REDSTONE_LAMP_ON: { - HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneLamp(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: { - HandleDropSpenser(a_X, dataitr->y, a_Z); + HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_WOODEN_DOOR: case E_BLOCK_IRON_DOOR: { - HandleDoor(a_X, dataitr->y, a_Z); + HandleDoor(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_POWERED_RAIL: { - HandleRail(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRail(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_WOODEN_PRESSURE_PLATE: @@ -300,7 +299,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: { - HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data); + HandlePressurePlate(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } default: LOGD("Unhandled block (!) or unimplemented redstone block: %s", ItemToString(dataitr->Data).c_str()); break; @@ -342,7 +341,7 @@ void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_Blo -void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { static const struct // Define which directions the torch can power { @@ -359,54 +358,58 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) { // Check if the block the torch is on is powered - int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on if (AreCoordsDirectlyPowered(X, Y, Z)) { // There was a match, torch goes off - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); return; } // Torch still on, make all 4(X, Z) + 1(Y) sides powered for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z); + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) + { + continue; + } if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) { if ( ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. - (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on + (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on ) { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } else { // Top side, power whatever is there, including blocks - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Power all blocks surrounding block above torch - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP); } } - if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath + if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath { - BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! { - SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } } else { // Check if the block the torch is on is powered - int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on // See if off state torch can be turned on again if (AreCoordsDirectlyPowered(X, Y, Z)) @@ -415,7 +418,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc } // Block torch on not powered, can be turned on again! - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); } } @@ -423,28 +426,47 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered } -void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (IsLeverOn(Meta)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER); + NIBBLETYPE Dir = cBlockLeverHandler::BlockMetaDataToBlockFace(Meta); + switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered() + { + case BLOCK_FACE_YP: + case BLOCK_FACE_XP: + case BLOCK_FACE_ZP: + { + Dir--; + break; + } + case BLOCK_FACE_XM: + case BLOCK_FACE_ZM: + case BLOCK_FACE_YM: + { + Dir++; + break; + } + default: + { + ASSERT(!"Unhandled lever metadata!"); + return; + } + } + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); } } @@ -452,27 +474,29 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleFenceGate(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; cChunkInterface ChunkInterface(m_World.GetChunkMap()); - NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData | 0x4); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData & 0xFFFFFFFB); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & 0xFFFFFFFB); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -481,18 +505,35 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, -void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) +void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (IsButtonOn(Meta)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType); - - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + + NIBBLETYPE Dir = cBlockButtonHandler::BlockMetaDataToBlockFace(Meta); + switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered() + { + case BLOCK_FACE_XP: + case BLOCK_FACE_ZP: + { + Dir--; + break; + } + case BLOCK_FACE_XM: + case BLOCK_FACE_ZM: + { + Dir++; + break; + } + default: + { + ASSERT(!"Unhandled button metadata!"); + return; + } + } + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); } } @@ -500,7 +541,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_Blo -void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { static const struct // Define which directions the wire can receive power from { @@ -535,14 +576,16 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block // Check to see if directly beside a power source unsigned char MyPower; - if (!IsWirePowered(a_BlockX, a_BlockY, a_BlockZ, MyPower)) + if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); return; } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MyPower); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); if (MyPower < 1) { @@ -555,74 +598,98 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block { if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... { - if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)... + BLOCKTYPE Type = 0; + if (a_RelBlockY + 1 >= cChunkDef::Height) + { + continue; + } + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type)) + { + continue; + } + if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... { continue; // We don't receive power from that wire } } else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us { - if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type)) + { + continue; + } + if (cBlockInfo::IsSolid(Type)) { continue; } } - if (m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z) == E_BLOCK_REDSTONE_WIRE) + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + continue; + } + if (Type == E_BLOCK_REDSTONE_WIRE) + { + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); } } for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them { - if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF) + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type)) { - SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + continue; + } + if (Type == E_BLOCK_REDSTONE_REPEATER_OFF) + { + SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); } } // Wire still powered, power blocks beneath - SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower); - switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) + switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { case REDSTONE_NONE: { - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); break; } case REDSTONE_X_POS: { - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); break; } case REDSTONE_X_NEG: { - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); break; } case REDSTONE_Z_POS: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); break; } case REDSTONE_Z_NEG: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); break; } } @@ -632,7 +699,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { /* Repeater Orientation Mini Guide: =================================== @@ -643,7 +710,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B X Axis ----> - Repeater directions, values from a cWorld::GetBlockMeta(a_BlockX , a_BlockY, a_BlockZ) lookup: + Repeater directions, values from a cWorld::GetBlockMeta(a_RelBlockX , a_RelBlockY, a_RelBlockZ) lookup: East (Right) (X+): 0x1 West (Left) (X-): 0x3 @@ -656,25 +723,25 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B */ // Create a variable holding my meta to avoid multiple lookups. - NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE a_Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); - if (!IsRepeaterLocked(a_BlockX, a_BlockY, a_BlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: + if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: { - bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta); + bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta); if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true); + QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true); } else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false); + QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false); } } for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -685,33 +752,33 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B { if (!IsOn) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance } switch (a_Meta & 0x3) // We only want the direction (bottom) bits { case 0x0: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM); break; } case 0x1: { - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP); break; } case 0x2: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP); break; } case 0x3: { - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM); break; } } @@ -724,7 +791,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B { if (IsOn) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } m_RepeatersDelayList->erase(itr); // We can remove off repeaters which don't need further updating return; @@ -735,7 +802,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B // Apparently, incrementing ticks only works reliably here, and not in SimChunk; // With a world with lots of redstone, the repeaters simply do not delay // I am confounded to say why. Perhaps optimisation failure. - LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); + LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); itr->a_ElapsedTicks++; } } @@ -745,16 +812,19 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B -void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { cPiston Piston(&m_World); - if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) { - Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ); + Piston.ExtendPiston(BlockX, a_RelBlockY, BlockZ); } else { - Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ); + Piston.RetractPiston(BlockX, a_RelBlockY, BlockZ); } } @@ -762,7 +832,7 @@ void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int -void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { class cSetPowerToDropSpenser : public cDropSpenserCallback @@ -776,29 +846,31 @@ void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY a_DropSpenser->SetRedstonePower(m_IsPowered); return false; } - } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + } DrSpSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithDropSpenserAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); } -void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); } } else { - if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } } } @@ -807,13 +879,16 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); - m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom + m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0); + m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom } } @@ -821,26 +896,29 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_ -void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { cChunkInterface ChunkInterface(m_World.GetChunkMap()); - cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { cChunkInterface ChunkInterface(m_World.GetChunkMap()); - cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -849,7 +927,7 @@ void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a -void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { class cSetPowerToCommandBlock : public cCommandBlockCallback @@ -863,37 +941,39 @@ void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_Block a_CommandBlock->SetRedstonePower(m_IsPowered); return false; } - } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + } CmdBlockSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithCommandBlockAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP); } -void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) { switch (a_MyType) { case E_BLOCK_DETECTOR_RAIL: { - if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) + if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType); } break; } case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_POWERED_RAIL: { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08); } else { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07); } break; } @@ -905,22 +985,25 @@ void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a -void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { - m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, true); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, false); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -929,13 +1012,13 @@ void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, i -void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ); + bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (m_bAreCoordsPowered) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { class cSetPowerToNoteBlock : public cNoteBlockCallback @@ -954,15 +1037,17 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, } } NoteBlockSP(m_bAreCoordsPowered); - m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithNoteBlockAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -971,10 +1056,10 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, -void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int a_ChunkX, a_ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ); + cChunkDef::BlockToChunk(a_RelBlockX, a_RelBlockZ, a_ChunkX, a_ChunkZ); if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ)) { @@ -982,10 +1067,12 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo } else { - NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness(); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + NIBBLETYPE SkyLight = m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)); if (SkyLight > 8) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } } @@ -994,24 +1081,28 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo -void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) { + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + switch (a_MyType) { 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(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false); + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.7f, false); if (a_Player != NULL) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } else { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); } break; } @@ -1056,95 +1147,98 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc int m_Z; }; - cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); m_World.ForEachEntity(PressurePlateCallback); unsigned char Power; - NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (PressurePlateCallback.GetPowerLevel(Power)) { if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + 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.5F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } else { if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); } break; } case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: - {class cPressurePlateCallback : - public cEntityCallback { - public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : - m_NumberOfEntities(0), - m_X(a_BlockX), - m_Y(a_BlockY), - m_Z(a_BlockZ) - { - } - - virtual bool Item(cEntity * a_Entity) override + class cPressurePlateCallback : + public cEntityCallback { - Vector3f EntityPos = a_Entity->GetPosition(); - Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); - double Distance = (EntityPos - BlockPos).Length(); + public: + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_NumberOfEntities(0), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } - if (Distance <= 0.7) + virtual bool Item(cEntity * a_Entity) override { - m_NumberOfEntities++; + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + double Distance = (EntityPos - BlockPos).Length(); + + if (Distance <= 0.7) + { + m_NumberOfEntities++; + } + return false; } - return false; - } - bool GetPowerLevel(unsigned char & a_PowerLevel) const - { - a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); - return (a_PowerLevel > 0); - } + bool GetPowerLevel(unsigned char & a_PowerLevel) const + { + a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); + return (a_PowerLevel > 0); + } - protected: - int m_NumberOfEntities; + protected: + int m_NumberOfEntities; - int m_X; - int m_Y; - int m_Z; - }; + int m_X; + int m_Y; + int m_Z; + }; - cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); - m_World.ForEachEntity(PressurePlateCallback); + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); + m_World.ForEachEntity(PressurePlateCallback); - unsigned char Power; - NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (PressurePlateCallback.GetPowerLevel(Power)) - { - if (Meta == E_META_PRESSURE_PLATE_RAISED) + unsigned char Power; + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) { - m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + if (Meta == E_META_PRESSURE_PLATE_RAISED) + { + 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.5F); + } + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); - } - else - { - if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + else { - m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + { + 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); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); - } break; } @@ -1189,27 +1283,28 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc int m_Z; } ; - cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ); + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); m_World.ForEachEntity(PressurePlateCallback); - NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (PressurePlateCallback.FoundEntity()) { if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + 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.5F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } else { if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); } break; } @@ -1225,11 +1320,15 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc -bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall + for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } @@ -1241,11 +1340,14 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(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; + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } @@ -1258,35 +1360,37 @@ bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_B // IsRepeaterPowered tests if a repeater should be powered by testing for power sources behind the repeater. // It takes the coordinates of the repeater the the meta value. -bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) +bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) { // Repeaters cannot be powered by any face except their back; verify that this is true for a source + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } switch (a_Meta & 0x3) { case 0x0: { // Flip the coords to check the back of the repeater - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; } break; } case 0x1: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; } break; } case 0x2: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; } break; } case 0x3: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; } break; } } @@ -1294,28 +1398,28 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } switch (a_Meta & 0x3) { case 0x0: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; } break; } case 0x1: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; } break; } case 0x2: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; } break; } case 0x3: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; } break; } } @@ -1327,7 +1431,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY -bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) +bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata { @@ -1336,16 +1440,17 @@ bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_BlockX, int a_BlockY, case 0x2: { // Check if eastern(right) neighbor is a powered on repeater who is facing us. - if (m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) == E_BLOCK_REDSTONE_REPEATER_ON) // Is right neighbor a powered repeater? + BLOCKTYPE Block = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater? { - NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX + 1, a_BlockY, a_BlockZ) & 0x3; + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ) & 0x3; if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked. } // Check if western(left) neighbor is a powered on repeater who is facing us. - if (m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) == E_BLOCK_REDSTONE_REPEATER_ON) + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) { - NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX -1, a_BlockY, a_BlockZ) & 0x3; + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX -1, a_RelBlockY, a_RelBlockZ) & 0x3; if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked. } @@ -1357,16 +1462,17 @@ bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_BlockX, int a_BlockY, case 0x3: { // Check if southern(down) neighbor is a powered on repeater who is facing us. - if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) == E_BLOCK_REDSTONE_REPEATER_ON) + BLOCKTYPE Block = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) { - NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ + 1) & 0x3; + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1) & 0x3; if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked. } // Check if northern(up) neighbor is a powered on repeater who is facing us. - if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ -1) == E_BLOCK_REDSTONE_REPEATER_ON) + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) { - NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ - 1) & 0x3; + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1) & 0x3; if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked. } @@ -1380,43 +1486,45 @@ bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_BlockX, int a_BlockY, -bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) +bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) { // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement - int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ; + int OldX = a_RelBlockX, OldY = a_RelBlockY, OldZ = a_RelBlockZ; eBlockFace Face = cPiston::MetaDataToDirection(a_Meta); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face); + AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face); - if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } - a_BlockX = OldX; - a_BlockY = OldY; - a_BlockZ = OldZ; + a_RelBlockX = OldX; + a_RelBlockY = OldY; + a_RelBlockZ = OldZ; } for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face); + AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face); - if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } - a_BlockX = OldX; - a_BlockY = OldY; - a_BlockZ = OldZ; + a_RelBlockX = OldX; + a_RelBlockY = OldY; + a_RelBlockZ = OldZ; } return false; // Source was in front of the piston's front face } @@ -1424,13 +1532,15 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, -bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ, unsigned char & a_PowerLevel) +bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel) { a_PowerLevel = 0; + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } @@ -1439,7 +1549,7 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, in for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } @@ -1453,11 +1563,11 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, in -bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered) +bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered) { for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? { @@ -1476,79 +1586,98 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType, unsigned char a_PowerLevel) +void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel) { + BLOCKTYPE MiddleBlock = 0; switch (a_Direction) { case BLOCK_FACE_XM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_XP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_YM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_YP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_ZM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_ZP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } @@ -1564,7 +1693,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int -void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel) +void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) { static const struct { @@ -1572,16 +1701,16 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc } gCrossCoords[] = { { 1, 0, 0 }, - {-1, 0, 0 }, + { -1, 0, 0 }, { 0, 0, 1 }, - { 0, 0,-1 }, + { 0, 0, -1 }, { 0, 1, 0 }, - { 0,-1, 0 } + { 0, -1, 0 } }; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock, a_PowerLevel); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_PowerLevel); } } @@ -1589,39 +1718,45 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel) +void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel) { - BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; + int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; + + BLOCKTYPE Block = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block)) + { + return; + } if (Block == E_BLOCK_AIR) { // Don't set air, fixes some bugs (wires powering themselves) return; } - PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); + PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list { if ( - itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && - itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) - ) + itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && + itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) + ) { - // Check for duplicates, update power level if everything else the same but either way, don't add a new listing - if (itr->a_PowerLevel != a_PowerLevel) - { - itr->a_PowerLevel = a_PowerLevel; - } + // Check for duplicates, update power level, don't add a new listing + itr->a_PowerLevel = a_PowerLevel; return; } } - PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); + PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list { if ( - itr->a_BlockPos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) && - itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) - ) + itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) && + itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) + ) { // Powered wires try to power their source - don't let them! return; @@ -1629,8 +1764,8 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, } sPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); - RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ); + RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ); RC.a_PowerLevel = a_PowerLevel; Powered->push_back(RC); } @@ -1640,45 +1775,57 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( - int a_BlockX, int a_BlockY, int a_BlockZ, - int a_MiddleX, int a_MiddleY, int a_MiddleZ, - int a_SourceX, int a_SourceY, int a_SourceZ, - BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel -) + int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, + int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, + int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, + BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel + ) { - BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + int MiddleX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelMiddleX; + int MiddleZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelMiddleZ; + int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; + int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; + + BLOCKTYPE DestBlock = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock)) + { + return; + } if (DestBlock == E_BLOCK_AIR) { // Don't set air, fixes some bugs (wires powering themselves) return; } + if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)) + { + return; + } if (!IsViableMiddleBlock(a_MiddleBlock)) { return; } - LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); + LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list { if ( - itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && - itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) && - itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) + itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && + itr->a_MiddlePos.Equals(Vector3i(MiddleX, a_RelMiddleY, MiddleZ)) && + itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) ) { - // Check for duplicates, update power level if everything else the same but either way, don't add a new listing - if (itr->a_PowerLevel != a_PowerLevel) - { - itr->a_PowerLevel = a_PowerLevel; - } + // Check for duplicates, update power level, don't add a new listing + itr->a_PowerLevel = a_PowerLevel; return; } } sLinkedPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); - RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); - RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ); + RC.a_MiddlePos = Vector3i(MiddleX, a_RelMiddleY, MiddleZ); + RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ); RC.a_PowerLevel = a_PowerLevel; Linked->push_back(RC); } @@ -1687,11 +1834,11 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered) +void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered) { for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -1711,7 +1858,7 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl // We have arrive here; no block must be in list - add one sSimulatedPlayerToggleableList RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); RC.WasLastStatePowered = WasLastStatePowered; m_SimulatedPlayerToggleableBlocks->push_back(RC); } @@ -1720,11 +1867,11 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl -void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) +void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) { for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry { @@ -1741,7 +1888,7 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a // Self not in list, add self to list sRepeatersDelayList RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) // * 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility @@ -1757,52 +1904,64 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a -cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) +cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int Dir = REDSTONE_NONE; - BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); - if (IsPotentialSource(NegX)) + BLOCKTYPE NegX = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX)) { - Dir |= (REDSTONE_X_POS); + if (IsPotentialSource(NegX)) + { + Dir |= (REDSTONE_X_POS); + } } - BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); - if (IsPotentialSource(PosX)) + BLOCKTYPE PosX = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX)) { - Dir |= (REDSTONE_X_NEG); + if (IsPotentialSource(PosX)) + { + Dir |= (REDSTONE_X_NEG); + } } - BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); - if (IsPotentialSource(NegZ)) + BLOCKTYPE NegZ = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ)) { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + if (IsPotentialSource(NegZ)) { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; } - Dir |= REDSTONE_Z_POS; } - BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); - if (IsPotentialSource(PosZ)) + BLOCKTYPE PosZ = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ)) { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + if (IsPotentialSource(PosZ)) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; } - Dir |= REDSTONE_Z_NEG; } return (eRedstoneDirection)Dir; } diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index a42cce79a..233a3d408 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -55,13 +55,13 @@ private: struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player) { - Vector3i a_BlockPos; + Vector3i a_RelBlockPos; bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate }; struct sRepeatersDelayList // Define structure of list containing repeaters' delay states { - Vector3i a_BlockPos; + Vector3i a_RelBlockPos; unsigned char a_DelayTicks; // For how many ticks should the repeater delay unsigned char a_ElapsedTicks; // How much of the previous has been elapsed? bool ShouldPowerOn; // What happens when the delay time is fulfilled? @@ -91,80 +91,80 @@ private: /* ====== SOURCES ====== */ /** Handles the redstone torch */ - void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /** Handles the redstone block */ - void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles levers */ - void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles buttons */ - void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); + void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles daylight sensors */ - void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles pressure plates */ - void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); /* ==================== */ /* ====== CARRIERS ====== */ /** Handles redstone wire */ - void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles repeaters */ - void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /* ====================== */ /* ====== DEVICES ====== */ /** Handles pistons */ - void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles dispensers and droppers */ - void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles TNT (exploding) */ - void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles redstone lamps */ - void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /** Handles doords */ - void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles command blocks */ - void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles activator, detector, and powered rails */ - void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ - void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles fence gates */ - void HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles noteblocks */ - void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ===================== */ /* ====== Helper functions ====== */ /** Marks a block as powered */ - void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); + void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as being powered through another block */ - void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); + void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */ - void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered); + void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered); /** Marks the second block in a direction as linked powered */ - void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); + void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks all blocks immediately surrounding a coordinate as powered */ - void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); + void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Queues a repeater to be powered or unpowered */ - void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); + void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); /** Returns if a coordinate is powered or linked powered */ - bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); } + bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } /** Returns if a coordinate is in the directly powered blocks list */ - bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Returns if a coordinate is in the indirectly powered blocks list */ - bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ - bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered); + bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered); /** Returns if a repeater is powered */ - bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); /** Returns if a repeater is locked */ - bool IsRepeaterLocked(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); /** Returns if a piston is powered */ - bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); /** Returns if a wire is powered The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */ - bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ, unsigned char & a_PowerLevel); + bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel); /** Returns if lever metadata marks it as emitting power */ diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index f305ba61a..b8f34559f 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -64,7 +64,7 @@ void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); } } - m_TotalBlocks -= ChunkData.size(); + m_TotalBlocks -= (int)ChunkData.size(); ChunkData.clear(); } @@ -254,6 +254,10 @@ void cSandSimulator::FinishFalling( { // Rematerialize the material here: a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta); + if (a_FallingBlockType == E_BLOCK_ANVIL) + { + a_World->BroadcastSoundParticleEffect(1022, a_BlockX, a_BlockY, a_BlockZ, 0); + } return; } diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp index 78aff9d68..18d9b07e1 100644 --- a/src/Simulator/VanillaFluidSimulator.cpp +++ b/src/Simulator/VanillaFluidSimulator.cpp @@ -35,14 +35,16 @@ cVanillaFluidSimulator::cVanillaFluidSimulator( -void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) +void cVanillaFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) { + // Calculate the distance to the nearest "hole" in each direction: int Cost[4]; Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS); Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS); Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS); Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS); + // Find the minimum distance: int MinCost = InfiniteCost; for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i) { @@ -52,6 +54,7 @@ void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, in } } + // Spread in all directions where the distance matches the minimum: if (Cost[0] == MinCost) { SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta); @@ -86,7 +89,10 @@ int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int { return Cost; } - if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType)) + if ( + !IsPassableForFluid(BlockType) || // The block cannot be passed by the liquid ... + (IsAllowedBlock(BlockType) && (BlockMeta == 0)) // ... or if it is liquid, it is a source block + ) { return Cost; } diff --git a/src/Simulator/VanillaFluidSimulator.h b/src/Simulator/VanillaFluidSimulator.h index a9ea98b5a..89a56ca14 100644 --- a/src/Simulator/VanillaFluidSimulator.h +++ b/src/Simulator/VanillaFluidSimulator.h @@ -30,7 +30,7 @@ public: protected: // cFloodyFluidSimulator overrides: - virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override; + virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override; /** Recursively calculates the minimum number of blocks needed to descend a level. */ int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0); diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index 2a85649a1..71d64e71e 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -11,15 +11,15 @@ /// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2() -int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor) +int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor) { - uLongf CompressedSize = compressBound(a_Length); + uLongf CompressedSize = compressBound((uLong)a_Length); // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer! // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Compressed.resize(CompressedSize); - int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor); + int errorcode = compress2((Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef *)a_Data, (uLong)a_Length, a_Factor); if (errorcode != Z_OK) { return errorcode; @@ -33,14 +33,14 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, in /// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's uncompress() -int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize) +int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize) { // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer! // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Uncompressed.resize(a_UncompressedSize); uLongf UncompressedSize = (uLongf)a_UncompressedSize; // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error - int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, a_Length); + int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, (uLong)a_Length); if (errorcode != Z_OK) { return errorcode; @@ -63,7 +63,7 @@ int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compres z_stream strm; memset(&strm, 0, sizeof(strm)); strm.next_in = (Bytef *)a_Data; - strm.avail_in = a_Length; + strm.avail_in = (uInt)a_Length; strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); @@ -127,7 +127,7 @@ extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & z_stream strm; memset(&strm, 0, sizeof(strm)); strm.next_in = (Bytef *)a_Data; - strm.avail_in = a_Length; + strm.avail_in = (uInt)a_Length; strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); diff --git a/src/StringCompression.h b/src/StringCompression.h index c3a9eca91..038240797 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -10,10 +10,10 @@ /// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2() -extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor); +extern int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor); /// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress() -extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize); +extern int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize); /// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 33b04505f..7488a3073 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -247,18 +247,22 @@ int NoCaseCompare(const AString & s1, const AString & s2) -unsigned int RateCompareString(const AString & s1, const AString & s2 ) +size_t RateCompareString(const AString & s1, const AString & s2) { - unsigned int MatchedLetters = 0; - unsigned int s1Length = s1.length(); + size_t MatchedLetters = 0; + size_t s1Length = s1.length(); - if( s1Length > s2.length() ) return 0; // Definitely not a match + if (s1Length > s2.length()) + { + // Definitely not a match + return 0; + } - for (unsigned int i = 0; i < s1Length; i++) + for (size_t i = 0; i < s1Length; i++) { - char c1 = (char)toupper( s1[i] ); - char c2 = (char)toupper( s2[i] ); - if( c1 == c2 ) + char c1 = (char)toupper(s1[i]); + char c2 = (char)toupper(s2[i]); + if (c1 == c2) { ++MatchedLetters; } @@ -288,11 +292,11 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & // Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 -AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8) +AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8) { a_UTF8.clear(); a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size - for (int i = 0; i < a_NumShorts; i++) + for (size_t i = 0; i < a_NumShorts; i++) { int c = GetBEShort(&a_RawData[i * 2]); if (c < 0x80) diff --git a/src/StringUtils.h b/src/StringUtils.h index b69e47d3c..caad85aef 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -52,13 +52,13 @@ extern AString & StrToLower(AString & s); extern int NoCaseCompare(const AString & s1, const AString & s2); // tolua_export /// Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1.length()] -extern unsigned int RateCompareString(const AString & s1, const AString & s2 ); +extern size_t RateCompareString(const AString & s1, const AString & s2); /// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export /// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 -extern AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8); +extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8); /// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16 extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16); diff --git a/src/Tracer.cpp b/src/Tracer.cpp index 6da6b2ad7..be42430a5 100644 --- a/src/Tracer.cpp +++ b/src/Tracer.cpp @@ -219,6 +219,10 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int return false; } + if ((pos.y < 0) || (pos.y >= cChunkDef::Height)) + { + return false; + } BLOCKTYPE BlockID = m_World->GetBlock(pos.x, pos.y, pos.z); // Block is counted as a collision if we are not doing a line of sight and it is solid, // or if the block is not air and not water. That way mobs can still see underwater. @@ -226,7 +230,7 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int { BlockHitPosition = pos; int Normal = GetHitNormal(a_Start, End, pos ); - if(Normal > 0) + if (Normal > 0) { HitNormal = m_NormalTable[Normal-1]; } diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 87b4032e0..788974f9c 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -244,7 +244,7 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player) -void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) { for (int i = 0; i < m_NumSlots; i++) { @@ -264,7 +264,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ { NumFit = a_ItemStack.m_ItemCount; } - if (a_Apply) + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; @@ -596,6 +596,409 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSlotAreaAnvil: + +cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) : + cSlotAreaTemporary(3, a_ParentWindow), + m_MaximumCost(0) +{ +} + + + + + +void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + if (a_SlotNum != 2) + { + super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem); + UpdateResult(a_Player); + return; + } + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + if (a_ClickAction == caDblClick) + { + return; + } + + if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + + if (Slot.IsEmpty()) + { + return; + } + if (!DraggingItem.IsEmpty()) + { + if (!(DraggingItem.IsEqual(Slot) && ((DraggingItem.m_ItemCount + Slot.m_ItemCount) <= cItemHandler::GetItemHandler(Slot)->GetMaxStackSize()))) + { + return; + } + } + + if (!CanTakeResultItem(a_Player)) + { + return; + } + + cItem NewItem = cItem(Slot); + NewItem.m_ItemCount += DraggingItem.m_ItemCount; + + Slot.Empty(); + DraggingItem.Empty(); + SetSlot(a_SlotNum, a_Player, Slot); + + DraggingItem = NewItem; + OnTakeResult(a_Player); + + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) +{ + if (a_SlotNum != 2) + { + super::ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + UpdateResult(a_Player); + return; + } + + // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover: + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + + if (Slot.IsEmpty() || !CanTakeResultItem(a_Player)) + { + return; + } + + m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + if (Slot.IsEmpty()) + { + Slot.Empty(); + OnTakeResult(a_Player); + } + SetSlot(a_SlotNum, a_Player, Slot); + + // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them: + m_ParentWindow.BroadcastWholeWindow(); +} + + + + + +void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +{ + for (int i = 0; i < 2; i++) + { + const cItem * Slot = GetSlot(i, a_Player); + if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) + { + // Different items + continue; + } + int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + if (NumFit <= 0) + { + // Full stack already + continue; + } + if (NumFit > a_ItemStack.m_ItemCount) + { + NumFit = a_ItemStack.m_ItemCount; + } + if (a_ShouldApply) + { + cItem NewSlot(a_ItemStack); + NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; + SetSlot(i, a_Player, NewSlot); + } + a_ItemStack.m_ItemCount -= NumFit; + if (a_ItemStack.IsEmpty()) + { + UpdateResult(a_Player); + return; + } + } // for i - Slots + UpdateResult(a_Player); +} + + + + + +void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player) +{ + if (!a_Player.IsGameModeCreative()) + { + a_Player.DeltaExperience(cPlayer::XpForLevel(m_MaximumCost)); + } + SetSlot(0, a_Player, cItem()); + + if (m_StackSizeToBeUsedInRepair > 0) + { + const cItem * Item = GetSlot(1, a_Player); + if (!Item->IsEmpty() && (Item->m_ItemCount > m_StackSizeToBeUsedInRepair)) + { + cItem NewSecondItem(*Item); + NewSecondItem.m_ItemCount -= m_StackSizeToBeUsedInRepair; + SetSlot(1, a_Player, NewSecondItem); + } + else + { + SetSlot(1, a_Player, cItem()); + } + } + else + { + SetSlot(1, a_Player, cItem()); + } + m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player); + + m_MaximumCost = 0; + ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", NULL); + + int PosX, PosY, PosZ; + ((cAnvilWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); + + BLOCKTYPE Block; + NIBBLETYPE BlockMeta; + a_Player.GetWorld()->GetBlockTypeMeta(PosX, PosY, PosZ, Block, BlockMeta); + + cFastRandom Random; + if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && (Random.NextFloat(1.0F) < 0.12F)) + { + NIBBLETYPE Orientation = BlockMeta & 0x3; + NIBBLETYPE AnvilDamage = BlockMeta >> 2; + ++AnvilDamage; + + if (AnvilDamage > 2) + { + // Anvil will break + a_Player.GetWorld()->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, (NIBBLETYPE)0); + a_Player.GetWorld()->BroadcastSoundParticleEffect(1020, PosX, PosY, PosZ, 0); + a_Player.CloseWindow(false); + } + else + { + a_Player.GetWorld()->SetBlockMeta(PosX, PosY, PosZ, Orientation | (AnvilDamage << 2)); + a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0); + } + } + else + { + a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0); + } +} + + + + + +bool cSlotAreaAnvil::CanTakeResultItem(cPlayer & a_Player) +{ + return ( + ( + a_Player.IsGameModeCreative() || // Is the player in gamemode? + (a_Player.GetXpLevel() >= m_MaximumCost) // or the player have enough exp? + ) && + (!GetSlot(2, a_Player)->IsEmpty()) && // Is a item in the result slot? + (m_MaximumCost > 0) // When no maximum cost is set, the item isn't set from the UpdateResult() method and can't be a valid enchanting result. + ); +} + + + + + +void cSlotAreaAnvil::OnPlayerRemoved(cPlayer & a_Player) +{ + TossItems(a_Player, 0, 2); + super::OnPlayerRemoved(a_Player); +} + + + + + +void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) +{ + cItem Input(*GetSlot(0, a_Player)); + cItem SecondInput(*GetSlot(1, a_Player)); + cItem Output(*GetSlot(2, a_Player)); + + if (Input.IsEmpty() && !Output.IsEmpty()) + { + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + m_MaximumCost = 0; + m_StackSizeToBeUsedInRepair = 0; + int RepairCost = Input.m_RepairCost; + int NeedExp = 0; + bool IsEnchantBook = false; + if (!SecondInput.IsEmpty()) + { + IsEnchantBook = (SecondInput.m_ItemType == E_ITEM_ENCHANTED_BOOK); + + RepairCost += SecondInput.m_RepairCost; + if (Input.IsDamageable() && cItemHandler::GetItemHandler(Input)->CanRepairWithRawMaterial(SecondInput.m_ItemType)) + { + // Tool and armor repair with special item (iron / gold / diamond / ...) + int DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4); + if (DamageDiff <= 0) + { + // No enchantment + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + int x = 0; + while ((DamageDiff > 0) && (x < SecondInput.m_ItemCount)) + { + Input.m_ItemDamage -= DamageDiff; + NeedExp += std::max(1, DamageDiff / 100) + (int)Input.m_Enchantments.Count(); + DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4); + + ++x; + } + m_StackSizeToBeUsedInRepair = x; + } + else + { + // Tool and armor repair with two tools / armors + if (!IsEnchantBook && (!Input.IsSameType(SecondInput) || !Input.IsDamageable())) + { + // No enchantment + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + if ((Input.GetMaxDamage() > 0) && !IsEnchantBook) + { + int FirstDamageDiff = Input.GetMaxDamage() - Input.m_ItemDamage; + int SecondDamageDiff = SecondInput.GetMaxDamage() - SecondInput.m_ItemDamage; + int Damage = SecondDamageDiff + Input.GetMaxDamage() * 12 / 100; + + int NewItemDamage = Input.GetMaxDamage() - (FirstDamageDiff + Damage); + if (NewItemDamage > 0) + { + NewItemDamage = 0; + } + + if (NewItemDamage < Input.m_ItemDamage) + { + Input.m_ItemDamage = NewItemDamage; + NeedExp += std::max(1, Damage / 100); + } + } + + // TODO: Add enchantments. + } + } + + int NameChangeExp = 0; + const AString & RepairedItemName = ((cAnvilWindow*)&m_ParentWindow)->GetRepairedItemName(); + if (RepairedItemName.empty()) + { + // Remove custom name + if (!Input.m_CustomName.empty()) + { + NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5); + NeedExp += NameChangeExp; + Input.m_CustomName = ""; + } + } + else if (RepairedItemName != Input.m_CustomName) + { + // Change custom name + NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5); + NeedExp += NameChangeExp; + + if (!Input.m_CustomName.empty()) + { + RepairCost += NameChangeExp / 2; + } + + Input.m_CustomName = RepairedItemName; + } + + // TODO: Add enchantment exp cost. + + m_MaximumCost = RepairCost + NeedExp; + + if (NeedExp < 0) + { + Input.Empty(); + } + + if ((NameChangeExp == NeedExp) && (NameChangeExp > 0) && (m_MaximumCost >= 40)) + { + m_MaximumCost = 39; + } + if (m_MaximumCost >= 40 && !a_Player.IsGameModeCreative()) + { + Input.Empty(); + } + + if (!Input.IsEmpty()) + { + RepairCost = std::max(Input.m_RepairCost, SecondInput.m_RepairCost); + if (!Input.m_CustomName.empty()) + { + RepairCost -= 9; + } + RepairCost = std::max(RepairCost, 0); + RepairCost += 2; + Input.m_RepairCost = RepairCost; + } + + SetSlot(2, a_Player, Input); + m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) : diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 254722822..4da6a672f 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -9,6 +9,7 @@ #pragma once #include "../Inventory.h" +#include "Window.h" @@ -259,6 +260,43 @@ protected: +class cSlotAreaAnvil : + public cSlotAreaTemporary +{ + typedef cSlotAreaTemporary super; + +public: + cSlotAreaAnvil(cAnvilWindow & a_ParentWindow); + + // cSlotArea overrides: + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + // cSlotAreaTemporary overrides: + virtual void OnPlayerRemoved(cPlayer & a_Player) override; + + /** Can the player take the item from the slot? */ + bool CanTakeResultItem(cPlayer & a_Player); + + /** This function will call, when the player take the item from the slot. */ + void OnTakeResult(cPlayer & a_Player); + + /** Handles a click in the item slot. */ + void UpdateResult(cPlayer & a_Player); + +protected: + /** The maximum cost of repairing/renaming in the anvil. */ + int m_MaximumCost; + + /** The stack size of the second item where was used for repair */ + char m_StackSizeToBeUsedInRepair; +} ; + + + + + class cSlotAreaEnchanting : public cSlotAreaTemporary { diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 0a78578fc..46885390b 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -591,7 +591,7 @@ void cWindow::OnLeftPaintEnd(cPlayer & a_Player) const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots(); cItem ToDistribute(a_Player.GetDraggingItem()); - int ToEachSlot = (int)ToDistribute.m_ItemCount / SlotNums.size(); + int ToEachSlot = (int)ToDistribute.m_ItemCount / (int)SlotNums.size(); int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, ToEachSlot, SlotNums); @@ -805,6 +805,51 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cAnvilWindow: + +cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtAnvil, "Repair"), + m_RepairedItemName(""), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_AnvilSlotArea = new cSlotAreaAnvil(*this); + m_SlotAreas.push_back(m_AnvilSlotArea); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player) +{ + m_RepairedItemName = a_Name; + + if (a_Player != NULL) + { + m_AnvilSlotArea->UpdateResult(*a_Player); + } +} + + + + + +void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +{ + a_PosX = m_BlockX; + a_PosY = m_BlockY; + a_PosZ = m_BlockZ; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cEnchantingWindow: cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : diff --git a/src/UI/Window.h b/src/UI/Window.h index 1ca67bfd8..542dccb88 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -24,6 +24,7 @@ class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; class cSlotArea; +class cSlotAreaAnvil; class cWorld; typedef std::list<cPlayer *> cPlayerList; @@ -231,6 +232,32 @@ public: +class cAnvilWindow : + public cWindow +{ + typedef cWindow super; +public: + cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + + /** Gets the repaired item name. */ + AString GetRepairedItemName(void) const { return m_RepairedItemName; } + + /** Set the repaired item name. */ + void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player); + + /** Gets the Position from the Anvil */ + void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); + +protected: + cSlotAreaAnvil * m_AnvilSlotArea; + AString m_RepairedItemName; + int m_BlockX, m_BlockY, m_BlockZ; +} ; + + + + + class cEnchantingWindow : public cWindow { @@ -243,7 +270,7 @@ public: /** Return the Value of a Property */ int GetPropertyValue(int a_Property); - /** Set the Position Values to the Position of the Enchantment Table */ + /** Get the Position from the Enchantment Table */ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); cSlotArea * m_SlotArea; diff --git a/src/Vector3.h b/src/Vector3.h index 2c79f9ff1..fed776018 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -40,7 +40,6 @@ public: Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {} // tolua_begin - inline void Set(T a_x, T a_y, T a_z) { x = a_x; @@ -105,18 +104,18 @@ public: inline bool Equals(const Vector3<T> & a_Rhs) const { - return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z; - } - - inline bool operator == (const Vector3<T> & a_Rhs) const - { - return Equals(a_Rhs); + // Perform a bitwise comparison of the contents - we want to know whether this object is exactly equal + // To perform EPS-based comparison, use the EqualsEps() function + return ( + (memcmp(&x, &a_Rhs.x, sizeof(x)) == 0) && + (memcmp(&y, &a_Rhs.y, sizeof(y)) == 0) && + (memcmp(&z, &a_Rhs.z, sizeof(z)) == 0) + ); } - - inline bool operator < (const Vector3<T> & a_Rhs) + + inline bool EqualsEps(const Vector3<T> & a_Rhs, T a_Eps) const { - // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ? - return (x < a_Rhs.x) || (x == a_Rhs.x && y < a_Rhs.y) || (x == a_Rhs.x && y == a_Rhs.y && z < a_Rhs.z); + return (Abs(x - a_Rhs.x) < a_Eps) && (Abs(y - a_Rhs.y) < a_Eps) && (Abs(z - a_Rhs.z) < a_Eps); } inline void Move(T a_X, T a_Y, T a_Z) @@ -135,6 +134,16 @@ public: // tolua_end + inline bool operator != (const Vector3<T> & a_Rhs) const + { + return !Equals(a_Rhs); + } + + inline bool operator == (const Vector3<T> & a_Rhs) const + { + return Equals(a_Rhs); + } + inline void operator += (const Vector3<T> & a_Rhs) { x += a_Rhs.x; @@ -163,8 +172,16 @@ public: z *= a_v; } - // tolua_begin + inline Vector3<T> & operator = (const Vector3<T> & a_Rhs) + { + x = a_Rhs.x; + y = a_Rhs.y; + z = a_Rhs.z; + return *this; + } + // tolua_begin + inline Vector3<T> operator + (const Vector3<T>& a_Rhs) const { return Vector3<T>( @@ -217,7 +234,7 @@ public: */ inline double LineCoeffToXYPlane(const Vector3<T> & a_OtherEnd, T a_Z) const { - if (abs(z - a_OtherEnd.z) < EPS) + if (Abs(z - a_OtherEnd.z) < EPS) { return NO_INTERSECTION; } @@ -232,7 +249,7 @@ public: */ inline double LineCoeffToXZPlane(const Vector3<T> & a_OtherEnd, T a_Y) const { - if (abs(y - a_OtherEnd.y) < EPS) + if (Abs(y - a_OtherEnd.y) < EPS) { return NO_INTERSECTION; } @@ -247,7 +264,7 @@ public: */ inline double LineCoeffToYZPlane(const Vector3<T> & a_OtherEnd, T a_X) const { - if (abs(x - a_OtherEnd.x) < EPS) + if (Abs(x - a_OtherEnd.x) < EPS) { return NO_INTERSECTION; } @@ -260,7 +277,15 @@ public: /** Return value of LineCoeffToPlane() if the line is parallel to the plane. */ static const double NO_INTERSECTION; + +protected: + /** Returns the absolute value of the given argument. + Templatized because the standard library differentiates between abs() and fabs(). */ + static T Abs(T a_Value) + { + return (a_Value < 0) ? -a_Value : a_Value; + } }; // tolua_end diff --git a/src/World.cpp b/src/World.cpp index 5ac8e0a6e..807065bfa 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -394,10 +394,14 @@ void cWorld::InitializeSpawn(void) // For the debugging builds, don't make the server build too much world upon start: #if defined(_DEBUG) || defined(ANDROID_NDK) - int ViewDist = 9; + const int DefaultViewDist = 9; #else - int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is #endif // _DEBUG + cIniFile IniFile; + IniFile.ReadFile(m_IniFileName); + int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); + IniFile.WriteFile(m_IniFileName); LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str()); for (int x = 0; x < ViewDist; x++) @@ -2402,13 +2406,13 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback) { cPlayer * BestMatch = NULL; - unsigned int BestRating = 0; - unsigned int NameLength = a_PlayerNameHint.length(); + size_t BestRating = 0; + size_t NameLength = a_PlayerNameHint.length(); cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { - unsigned int Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName()); + size_t Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName()); if (Rating >= BestRating) { BestMatch = *itr; @@ -2422,7 +2426,6 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa if (BestMatch != NULL) { - LOG("Compared %s and %s with rating %i", a_PlayerNameHint.c_str(), BestMatch->GetName().c_str(), BestRating); return a_Callback.Item (BestMatch); } return false; diff --git a/src/World.h b/src/World.h index f789916df..86cbb3e7e 100644 --- a/src/World.h +++ b/src/World.h @@ -351,7 +351,7 @@ public: /** Is the trapdoor open? Returns false if there is no trapdoor at the specified coords. */ bool IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - /** Set the state of a trapdoor. Returns true if the trapdoor was update, false if there was no trapdoor at those coords. */ + /** Set the state of a trapdoor. Returns true if the trapdoor was updated, false if there was no trapdoor at those coords. */ bool SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open); // tolua_export /** Regenerate the given chunk: */ @@ -710,7 +710,9 @@ public: virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) override; // tolua_export int SpawnMobFinalize(cMonster* a_Monster); - /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */ + /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise + Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata + */ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export /** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */ diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index ac9a21205..a047d67c7 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -29,7 +29,7 @@ // cParsedNBT: #define NEEDBYTES(N) \ - if (m_Length - m_Pos < N) \ + if (m_Length - m_Pos < (size_t)N) \ { \ return false; \ } @@ -38,7 +38,7 @@ -cParsedNBT::cParsedNBT(const char * a_Data, int a_Length) : +cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) : m_Data(a_Data), m_Length(a_Length), m_Pos(0) @@ -79,14 +79,14 @@ bool cParsedNBT::Parse(void) -bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen) +bool cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen) { NEEDBYTES(2); a_StringStart = m_Pos + 2; - a_StringLen = GetBEShort(m_Data + m_Pos); - if (a_StringLen < 0) + a_StringLen = (size_t)GetBEShort(m_Data + m_Pos); + if (a_StringLen > 0xffff) { - // Invalid string length + // Suspicious string length return false; } m_Pos += 2 + a_StringLen; @@ -99,8 +99,10 @@ bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen) bool cParsedNBT::ReadCompound(void) { + ASSERT(m_Tags.size() > 0); + // Reads the latest tag as a compound - int ParentIdx = m_Tags.size() - 1; + int ParentIdx = (int)m_Tags.size() - 1; int PrevSibling = -1; for (;;) { @@ -114,13 +116,13 @@ bool cParsedNBT::ReadCompound(void) m_Tags.push_back(cFastNBTTag(TagType, ParentIdx, PrevSibling)); if (PrevSibling >= 0) { - m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1; + m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1; } else { - m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1; + m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1; } - PrevSibling = m_Tags.size() - 1; + PrevSibling = (int)m_Tags.size() - 1; RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); RETURN_FALSE_IF_FALSE(ReadTag()); } // while (true) @@ -146,20 +148,20 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) } // Read items: - int ParentIdx = m_Tags.size() - 1; + int ParentIdx = (int)m_Tags.size() - 1; int PrevSibling = -1; for (int i = 0; i < Count; i++) { m_Tags.push_back(cFastNBTTag(a_ChildrenType, ParentIdx, PrevSibling)); if (PrevSibling >= 0) { - m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1; + m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1; } else { - m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1; + m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1; } - PrevSibling = m_Tags.size() - 1; + PrevSibling = (int)m_Tags.size() - 1; RETURN_FALSE_IF_FALSE(ReadTag()); } // for (i) m_Tags[ParentIdx].m_LastChild = PrevSibling; @@ -279,7 +281,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen for (int Child = m_Tags[a_Tag].m_FirstChild; Child != -1; Child = m_Tags[Child].m_NextSibling) { if ( - (m_Tags[Child].m_NameLength == (int)a_NameLength) && + (m_Tags[Child].m_NameLength == a_NameLength) && (memcmp(m_Data + m_Tags[Child].m_NameStart, a_Name, a_NameLength) == 0) ) { @@ -336,7 +338,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) : m_Stack[0].m_Type = TAG_Compound; m_Result.reserve(100 * 1024); m_Result.push_back(TAG_Compound); - WriteString(a_RootTagName.data(), a_RootTagName.size()); + WriteString(a_RootTagName.data(), (UInt16)a_RootTagName.size()); } @@ -389,7 +391,7 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType) ++m_CurrentStack; m_Stack[m_CurrentStack].m_Type = TAG_List; - m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4; + m_Stack[m_CurrentStack].m_Pos = (int)m_Result.size() - 4; m_Stack[m_CurrentStack].m_Count = 0; m_Stack[m_CurrentStack].m_ItemType = a_ChildrenType; } @@ -493,7 +495,7 @@ void cFastNBTWriter::AddString(const AString & a_Name, const AString & a_Value) void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_ByteArray); - Int32 len = htonl(a_NumElements); + u_long len = htonl((u_long)a_NumElements); m_Result.append((const char *)&len, 4); m_Result.append(a_Value, a_NumElements); } @@ -505,7 +507,7 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_IntArray); - Int32 len = htonl(a_NumElements); + u_long len = htonl((u_long)a_NumElements); size_t cap = m_Result.capacity(); size_t size = m_Result.length(); if ((cap - size) < (4 + a_NumElements * 4)) @@ -534,7 +536,7 @@ void cFastNBTWriter::Finish(void) -void cFastNBTWriter::WriteString(const char * a_Data, short a_Length) +void cFastNBTWriter::WriteString(const char * a_Data, UInt16 a_Length) { Int16 Len = htons(a_Length); m_Result.append((const char *)&Len, 2); diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index bcf93228f..fe28005ac 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -61,10 +61,10 @@ public: // The following members are indices into the data stream. m_DataLength == 0 if no data available // They must not be pointers, because the datastream may be copied into another AString object in the meantime. - int m_NameStart; - int m_NameLength; - int m_DataStart; - int m_DataLength; + size_t m_NameStart; + size_t m_NameLength; + size_t m_DataStart; + size_t m_DataLength; // The following members are indices into the array returned; -1 if not valid // They must not be pointers, because pointers would not survive std::vector reallocation @@ -114,7 +114,7 @@ Each primitive tag also stores the length of the contained data, in bytes. class cParsedNBT { public: - cParsedNBT(const char * a_Data, int a_Length); + cParsedNBT(const char * a_Data, size_t a_Length); bool IsValid(void) const {return m_IsValid; } @@ -135,7 +135,7 @@ public: /** Returns the length of the tag's data, in bytes. Not valid for Compound or List tags! */ - int GetDataLength (int a_Tag) const + size_t GetDataLength (int a_Tag) const { ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List); ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound); @@ -251,15 +251,15 @@ public: protected: const char * m_Data; - int m_Length; + size_t m_Length; std::vector<cFastNBTTag> m_Tags; bool m_IsValid; // True if parsing succeeded // Used while parsing: - int m_Pos; + size_t m_Pos; bool Parse(void); - bool ReadString(int & a_StringStart, int & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors + bool ReadString(size_t & a_StringStart, size_t & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors bool ReadCompound(void); // Reads the latest tag as a compound bool ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType bool ReadTag(void); // Reads the latest tag, depending on its m_Type setting @@ -319,7 +319,7 @@ protected: bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); } - void WriteString(const char * a_Data, short a_Length); + void WriteString(const char * a_Data, UInt16 a_Length); inline void TagCommon(const AString & a_Name, eTagType a_Type) { @@ -330,7 +330,7 @@ protected: { // Compound: add the type and name: m_Result.push_back((char)a_Type); - WriteString(a_Name.c_str(), (short)a_Name.length()); + WriteString(a_Name.c_str(), (UInt16)a_Name.length()); } else { diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index e0cd69634..181cfde0d 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -96,7 +96,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB if (ExplosionName == "Colors") { // Divide by four as data length returned in bytes - int DataLength = a_NBT.GetDataLength(explosiontag); + size_t DataLength = a_NBT.GetDataLength(explosiontag); // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) @@ -105,14 +105,14 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB } const char * ColourData = (a_NBT.GetData(explosiontag)); - for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) + for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i)); } } else if (ExplosionName == "FadeColors") { - int DataLength = a_NBT.GetDataLength(explosiontag) / 4; + size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4; // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) @@ -121,7 +121,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB } const char * FadeColourData = (a_NBT.GetData(explosiontag)); - for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) + for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i)); } diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp index df72d1cc9..012fc52f3 100644 --- a/src/WorldStorage/MapSerializer.cpp +++ b/src/WorldStorage/MapSerializer.cpp @@ -152,6 +152,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) if (CurrLine >= 0) { unsigned int Width = a_NBT.GetShort(CurrLine); + if (Width != 128) + { + return false; + } m_Map->m_Width = Width; } @@ -159,6 +163,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) if (CurrLine >= 0) { unsigned int Height = a_NBT.GetShort(CurrLine); + if (Height >= 256) + { + return false; + } m_Map->m_Height = Height; } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index fd356c7de..2ac1d7962 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -88,23 +88,48 @@ void cNBTChunkSerializer::Finish(void) void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName) { m_Writer.BeginCompound(a_CompoundName); - m_Writer.AddShort("id", (short)(a_Item.m_ItemType)); - m_Writer.AddShort("Damage", a_Item.m_ItemDamage); - m_Writer.AddByte ("Count", a_Item.m_ItemCount); + m_Writer.AddShort("id", (short)(a_Item.m_ItemType)); + m_Writer.AddShort("Damage", a_Item.m_ItemDamage); + m_Writer.AddByte ("Count", a_Item.m_ItemCount); if (a_Slot >= 0) { m_Writer.AddByte ("Slot", (unsigned char)a_Slot); } - // Write the enchantments: - if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))) + // Write the tag compound (for enchantment, firework, custom name and repair cost): + if ( + (!a_Item.m_Enchantments.IsEmpty()) || + ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) || + (a_Item.m_RepairCost > 0) || + (a_Item.m_CustomName != "") || + (a_Item.m_Lore != "") + ) { m_Writer.BeginCompound("tag"); + if (a_Item.m_RepairCost > 0) + { + m_Writer.AddInt("RepairCost", a_Item.m_RepairCost); + } + + if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != "")) + { + m_Writer.BeginCompound("display"); + if (a_Item.m_CustomName != "") + { + m_Writer.AddString("Name", a_Item.m_CustomName); + } + if (a_Item.m_Lore != "") + { + m_Writer.AddString("Lore", a_Item.m_Lore); + } + m_Writer.EndCompound(); + } + if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) { cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType); } - + if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; @@ -490,7 +515,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) } case cMonster::mtMagmaCube: { - m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize()); + m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize()); break; } case cMonster::mtSheep: diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp index 9d594a084..1cf99efd9 100644 --- a/src/WorldStorage/SchematicFileSerializer.cpp +++ b/src/WorldStorage/SchematicFileSerializer.cpp @@ -192,7 +192,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP int SizeX = a_NBT.GetShort(TSizeX); int SizeY = a_NBT.GetShort(TSizeY); int SizeZ = a_NBT.GetShort(TSizeZ); - if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1)) + if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > 256) || (SizeZ < 1) || (SizeZ > 65535)) { LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ); return false; @@ -230,11 +230,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP } // Copy the block types and metas: - int NumBytes = a_BlockArea.GetBlockCount(); + size_t NumBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockTypes) < NumBytes) { LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockTypes) + (int)NumBytes, (int)a_NBT.GetDataLength(TBlockTypes) ); NumBytes = a_NBT.GetDataLength(TBlockTypes); } @@ -242,11 +242,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP if (AreMetasPresent) { - int NumBytes = a_BlockArea.GetBlockCount(); + size_t NumBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockMetas) < NumBytes) { LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockMetas) + (int)NumBytes, (int)a_NBT.GetDataLength(TBlockMetas) ); NumBytes = a_NBT.GetDataLength(TBlockMetas); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index f33178173..d310c9124 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -96,7 +96,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : gzFile gz = gzopen((FILE_IO_PREFIX + fnam).c_str(), "wb"); if (gz != NULL) { - gzwrite(gz, Writer.GetResult().data(), Writer.GetResult().size()); + gzwrite(gz, Writer.GetResult().data(), (unsigned)Writer.GetResult().size()); } gzclose(gz); } @@ -252,7 +252,7 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & strm.next_out = (Bytef *)Uncompressed; strm.avail_out = sizeof(Uncompressed); strm.next_in = (Bytef *)a_Data.data(); - strm.avail_in = a_Data.size(); + strm.avail_in = (uInt)a_Data.size(); int res = inflate(&strm, Z_FINISH); inflateEnd(&strm); if (res != Z_STREAM_END) @@ -405,7 +405,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT -void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length) +void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length) { int Child = a_NBT.FindChildByName(a_Tag, a_ChildName); if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length)) @@ -440,8 +440,8 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_ // Save blockdata: a_Writer.BeginList("Sections", TAG_Compound); - int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16; - int SliceSizeNibble = SliceSizeBlock / 2; + size_t SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16; + size_t SliceSizeNibble = SliceSizeBlock / 2; const char * BlockTypes = (const char *)(Serializer.m_BlockTypes); const char * BlockMetas = (const char *)(Serializer.m_BlockMetas); #ifdef DEBUG_SKYLIGHT @@ -645,18 +645,16 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ } int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage"); - if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short)) + if ((Damage > 0) && (a_NBT.GetType(Damage) == TAG_Short)) { - return false; + a_Item.m_ItemDamage = a_NBT.GetShort(Damage); } - a_Item.m_ItemDamage = a_NBT.GetShort(Damage); int Count = a_NBT.FindChildByName(a_TagIdx, "Count"); - if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte)) + if ((Count > 0) && (a_NBT.GetType(Count) == TAG_Byte)) { - return false; + a_Item.m_ItemCount = a_NBT.GetByte(Count); } - a_Item.m_ItemCount = a_NBT.GetByte(Count); // Find the "tag" tag, used for enchantments and other extra data int TagTag = a_NBT.FindChildByName(a_TagIdx, "tag"); @@ -666,6 +664,29 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ return true; } + // Load repair cost: + int RepairCost = a_NBT.FindChildByName(TagTag, "RepairCost"); + if ((RepairCost > 0) && (a_NBT.GetType(RepairCost) == TAG_Int)) + { + a_Item.m_RepairCost = a_NBT.GetInt(RepairCost); + } + + // Load display name: + int DisplayTag = a_NBT.FindChildByName(TagTag, "display"); + if (DisplayTag > 0) + { + int DisplayName = a_NBT.FindChildByName(DisplayTag, "Name"); + if ((DisplayName > 0) && (a_NBT.GetType(DisplayName) == TAG_String)) + { + a_Item.m_CustomName = a_NBT.GetString(DisplayName); + } + int Lore = a_NBT.FindChildByName(DisplayTag, "Lore"); + if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String)) + { + a_Item.m_Lore = a_NBT.GetString(Lore); + } + } + // Load enchantments: const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; int EnchTag = a_NBT.FindChildByName(TagTag, EnchName); @@ -674,6 +695,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag); } + // Load firework data: int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion")); if (EnchTag > 0) { @@ -1056,7 +1078,7 @@ void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, cons -void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) +void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength) { if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) { @@ -1974,7 +1996,10 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT { int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); - if (SizeIdx < 0) { return; } + if (SizeIdx < 0) + { + return; + } int Size = a_NBT.GetInt(SizeIdx); @@ -2132,7 +2157,10 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ { int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); - if (SizeIdx < 0) { return; } + if (SizeIdx < 0) + { + return; + } int Size = a_NBT.GetInt(SizeIdx); @@ -2602,14 +2630,14 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]); unsigned ChunkOffset = ChunkLocation >> 8; - m_File.Seek(ChunkOffset * 4096); + m_File.Seek((int)ChunkOffset * 4096); int ChunkSize = 0; if (m_File.Read(&ChunkSize, 4) != 4) { return false; } - ChunkSize = ntohl(ChunkSize); + ChunkSize = ntohl((u_long)ChunkSize); char CompressionType = 0; if (m_File.Read(&CompressionType, 1) != 1) { @@ -2654,7 +2682,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri // Store the chunk data: m_File.Seek(ChunkSector * 4096); - unsigned ChunkSize = htonl(a_Data.size() + 1); + u_long ChunkSize = htonl((u_long)a_Data.size() + 1); if (m_File.Write(&ChunkSize, 4) != 4) { LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str()); @@ -2678,7 +2706,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri m_File.Write(Padding, 4096 - (BytesWritten % 4096)); // Store the header: - ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number + ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number ASSERT(ChunkSize < 256); m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize); if (m_File.Seek(0) < 0) diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 1773ee882..7542a828a 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -145,7 +145,7 @@ protected: void LoadMobHeadFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); + void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength); void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); @@ -221,7 +221,7 @@ protected: cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk); /// Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer - void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length); + void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length); // cWSSchema overrides: virtual bool LoadChunk(const cChunkCoords & a_Chunk) override; diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index 359bac4a8..6d06b8fe3 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -601,7 +601,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Decompress the data: AString UncompressedData; { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize); + int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -681,7 +681,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -693,9 +693,9 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() } // Save into file's cache - Header->m_UncompressedSize = Converted.size(); - Header->m_CompressedSize = CompressedData.size(); - NewDataContents.append( CompressedData ); + Header->m_UncompressedSize = (int)Converted.size(); + Header->m_CompressedSize = (int)CompressedData.size(); + NewDataContents.append(CompressedData); } // Done converting @@ -731,7 +731,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() Offset += Header->m_CompressedSize; // Crude data integrity check: - const int ExpectedSize = (16*256*16)*2 + (16*256*16)/2; // For version 2 + const int ExpectedSize = (16 * 256 * 16) * 2 + (16 * 256 * 16) / 2; // For version 2 if (UncompressedSize < ExpectedSize) { LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing", @@ -745,7 +745,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() // Decompress the data: AString UncompressedData; { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize); + int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -829,9 +829,9 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() } // Save into file's cache - Header->m_UncompressedSize = Converted.size(); - Header->m_CompressedSize = CompressedData.size(); - NewDataContents.append( CompressedData ); + Header->m_UncompressedSize = (int)Converted.size(); + Header->m_CompressedSize = (int)CompressedData.size(); + NewDataContents.append(CompressedData); } // Done converting @@ -861,7 +861,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_Uncompre // Decompress the data: AString UncompressedData; - int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, a_UncompressedSize); + int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, (size_t)a_UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -873,7 +873,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_Uncompre if (a_UncompressedSize != (int)UncompressedData.size()) { - LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", + LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", a_UncompressedSize, UncompressedData.size(), a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ ); |