diff options
58 files changed, 684 insertions, 182 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index eceb19bd7..451b7364a 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -200,6 +200,8 @@ g_APIDesc = msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" }, msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" }, msLake = { Notes = "Special mode for merging lake images" }, + msSpongePrint = { Notes = "Similar to msImprint, sponge block doesn't overwrite anything, all other blocks overwrite everything"}, + msMask = { Notes = "The blocks that are exactly the same are kept in Dst, all differing blocks are replaced by air"}, }, ConstantGroups = { @@ -247,6 +249,9 @@ g_APIDesc = <tr> <td> A </td><td> B </td><td> B </td><td> A </td><td> B </td> </tr> + <tr> + <td> A </td><td> A </td><td> A </td><td> A </td><td> A </td> + </td> </tbody></table> <p> @@ -260,7 +265,20 @@ g_APIDesc = <h3>Special strategies</h3> <p>For each strategy, evaluate the table rows from top downwards, the first match wins.</p> - + + <p> + <strong>msDifference</strong> - changes all the blocks which are the same to air. Otherwise the source block gets placed. + </p> + <table><tbody<tr> + <th colspan="2"> area block </th><th> </th><th> Notes </th> + </tr><tr> + <td> * </td><td> B </td><td> B </td><td> The blocks are different so we use block B </td> + </tr><tr> + <td> B </td><td> B </td><td> Air </td><td> The blocks are the same so we get air. </td> + </tr> + </tbody></table> + + <p> <strong>msLake</strong> - used for merging areas with lava and water lakes, in the appropriate generator. </p> @@ -293,7 +311,6 @@ g_APIDesc = </tr> </tbody></table> - <p> <strong>msSpongePrint</strong> - used for most prefab-generators to merge the prefabs. Similar to msImprint, but uses the sponge block as the NOP block instead, so that the prefabs may carve out air @@ -306,10 +323,26 @@ g_APIDesc = </tr><tr> <td> A </td><td> sponge </td><td> A </td><td> Sponge is the NOP block </td> </tr><tr> - <td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td> + <td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td> </tr> </tbody></table> - ]], + + <p> + <strong>msMask</strong> - the blocks that are the same in the other area are kept, all the + differing blocks are replaced with air. Meta is used in the comparison, too, two blocks of the + same type but different meta are considered different and thus replaced with air. + </p> + <table><tbody><tr> + <th colspan="2"> area block </th><th> </th><th> Notes </th> + </tr><tr> + <th> this </th><th> Src </th><th> result </th><th> </th> + </tr><tr> + <td> A </td><td> A </td><td> A </td><td> Same blocks are kept </td> + </tr><tr> + <td> A </td><td> non-A </td><td> air </td><td> Differing blocks are replaced with air </td> + </tr> + </tbody></table> +]], }, -- Merge strategies }, -- AdditionalInfo }, -- cBlockArea @@ -2663,11 +2696,31 @@ end ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format 'ItemTypeText:ItemDamage * Count'"}, ItemToString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item type"}, ItemTypeToString = {Params = "ItemType", Return = "string", Notes = "Returns the string representation of ItemType "}, - LOG = {Params = "string", Notes = "Logs a text into the server console using 'normal' severity (gray text) "}, - LOGERROR = {Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"}, - LOGINFO = {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"}, - LOGWARN = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"}, - LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"}, + LOG = + { + {Params = "string", Notes = "Logs a text into the server console using 'normal' severity (gray text)"}, + {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console. The severity is converted from the CompositeChat's MessageType."}, + }, + LOGERROR = + { + {Params = "string", Notes = "Logs a text into the server console using 'error' severity (black text on red background)"}, + {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'error' severity (black text on red background)"}, + }, + LOGINFO = + { + {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"}, + {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'info' severity (yellow text)"}, + }, + LOGWARN = + { + {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"}, + {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"}, + }, + LOGWARNING = + { + {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"}, + {Params = "{{cCompositeChat|CompositeChat}}", Notes = "Logs the {{cCompositeChat}}'s human-readable text into the server console using 'warning' severity (red text)"}, + }, MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." }, NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"}, NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." }, diff --git a/MCServer/Plugins/APIDump/SettingUpZeroBrane.html b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html index 0fb89e49d..4ebbcb6e6 100644 --- a/MCServer/Plugins/APIDump/SettingUpZeroBrane.html +++ b/MCServer/Plugins/APIDump/SettingUpZeroBrane.html @@ -25,7 +25,8 @@ <h2><img src="Static/zbs_logo.png" /> First-time setup</h2> <p>Since ZBS is a universal Lua IDE, you need to first set it up so that it is ready for MCS plugin development. For that, you need to download one file, <a href="https://raw.githubusercontent.com/pkulchenko/ZeroBranePackage/master/mcserver.lua">mcserver.lua</a> from the <a href="https://github.com/pkulchenko/ZeroBranePackage">ZBS's plugin repository</a>. Place that file in the "packages" folder inside your ZBS's folder. Note that there are other useful plugins in the repository and you may want to have a look there later on to further customize your ZBS. To install them, simply save them into the same folder.</p> - <p>After you download the mcserver.lua file, you need to restart ZBS in order for the plugin to load. If there are no errors, you should see two new items in the Project -> Lua Interpreter submenu: "MCServer - debug mode" and "MCServer - release mode". The only difference between the two is which filename they use to launch MCServer - mcserver_debug(.exe) for the debug option and "mcserver(.exe)" for the release option. If you built your own MCServer executable and you built it in debug mode, you should select the debug mode option. In all other cases, including if you downloaded the already-compiled MCServer executable from the internet, you should select the release mode option.</p> + <p>Next you should install the code-completion support specific for MCServer. You should repeat this step from time to time, because the API evolves in time so new functions and classes are added to it quite often. You should have an APIDump plugin in your MCServer installation. Enable the APIDump plugin in the server settings, it's very cheap to keep it enabled and it doesn't cost any performance during normal gameplay. To generate the code-completion support file, enter the <code style="background: #ddd; border: 1px solid #aaa">api</code> command into the server console. This will create a new file, "mcserver_api.lua", next to the MCS executable. Move that file into the "api/lua" subfolder inside your ZBS's folder.</p> + <p>After you download the mcserver.lua file and install the completion support, you need to restart ZBS in order for the plugin to load. If there are no errors, you should see two new items in the Project -> Lua Interpreter submenu: "MCServer - debug mode" and "MCServer - release mode". The only difference between the two is which filename they use to launch MCServer - mcserver_debug(.exe) for the debug option and "mcserver(.exe)" for the release option. If you built your own MCServer executable and you built it in debug mode, you should select the debug mode option. In all other cases, including if you downloaded the already-compiled MCServer executable from the internet, you should select the release mode option.</p> <p>For a first time user, it might be a bit overwhelming that there are no GUI settings in the ZBS, yet the IDE is very configurable. There are two files that you edit in order to change settings, either system-wide (all users of the computer share those settings) or user-wide (the settings are only for a specific user of the computer). Those files are regular Lua sources and you can quickly locate them and edit them from within the IDE itself, select Edit -> Preferences -> Settings: XYZ from the menu, with XYZ being either System or User.</p> <p>There is a documentation on most of the settings on ZBS's webpage, have a look at <a href="http://studio.zerobrane.com/documentation.html">http://studio.zerobrane.com/documentation.html</a>, especially the Preferences section. Personally I recommend setting editor.usetabs to true and possibly adjusting the editor.tabwidth, turn off the editor.smartindent feature and for debugging the option debugger.alloweditting should be set to true unless you feel like punishing yourself.</p> diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index 7455c3cd2..52199740b 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -1408,9 +1408,9 @@ end --- Dumps the entire API table into a file in the ZBS format local function DumpAPIZBS(a_API) LOG("Dumping ZBS API description...") - local f, err = io.open("mcserver.lua", "w") + local f, err = io.open("mcserver_api.lua", "w") if (f == nil) then - LOG("Cannot open mcserver.lua for writing, ZBS API will not be dumped. " .. err) + LOG("Cannot open mcserver_lua.lua for writing, ZBS API will not be dumped. " .. err) return end diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 2cb014875..064d5d772 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -69,12 +69,22 @@ function Initialize(Plugin) LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) - -- TestBlockAreas(); - -- TestSQLiteBindings(); - -- TestExpatBindings(); - -- TestPluginCalls(); + -- TestBlockAreas() + -- TestSQLiteBindings() + -- TestExpatBindings() + -- TestPluginCalls() TestBlockAreasString() + TestStringBase64() + + --[[ + -- Test cCompositeChat usage in console-logging: + LOGINFO(cCompositeChat("This is a simple message with some @2 color formatting @4 and http://links.to .") + :AddSuggestCommandPart("(Suggested command)", "cmd") + :AddRunCommandPart("(Run command)", "cmd") + :SetMessageType(mtInfo) + ) + --]] return true end; @@ -243,6 +253,24 @@ end +function TestStringBase64() + -- Create a binary string: + local s = "" + for i = 0, 255 do + s = s .. string.char(i) + end + + -- Roundtrip through Base64: + local Base64 = Base64Encode(s) + local UnBase64 = Base64Decode(Base64) + + assert(UnBase64 == s) +end + + + + + function TestSQLiteBindings() LOG("Testing SQLite bindings..."); diff --git a/SetFlags.cmake b/SetFlags.cmake index bbd8254ad..c5a3a0697 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -198,6 +198,7 @@ macro(set_exe_flags) add_flags_cxx("-Wno-error=covered-switch-default -Wno-error=shadow") add_flags_cxx("-Wno-error=exit-time-destructors -Wno-error=missing-variable-declarations") add_flags_cxx("-Wno-error=global-constructors -Wno-implicit-fallthrough") + add_flags_cxx("-Wno-weak-vtables -Wno-switch-enum -Wno-exit-time-destructors") endif() endif() diff --git a/lib/md5/md5.h b/lib/md5/md5.h index ad5ad5384..3aa88ac22 100644 --- a/lib/md5/md5.h +++ b/lib/md5/md5.h @@ -90,4 +90,4 @@ private: std::string md5(const std::string & str); -#endif
\ No newline at end of file +#endif diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp index 408b1b84a..fbc008be6 100644 --- a/src/Bindings/DeprecatedBindings.cpp +++ b/src/Bindings/DeprecatedBindings.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "DeprecatedBindings.h" +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Plugin.h" diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 13eb17f7d..a33459ad2 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -11,6 +11,7 @@ extern "C" #include "lua/src/lualib.h" } +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Bindings.h" #include "ManualBindings.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 20bbc48f2..92b410481 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ManualBindings.h" +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Plugin.h" @@ -115,10 +116,44 @@ static int tolua_StringSplitAndTrim(lua_State * tolua_S) -static int tolua_LOG(lua_State* tolua_S) +/** Retrieves the log message from the first param on the Lua stack. +Can take either a string or a cCompositeChat. +*/ +static AString GetLogMessage(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 0 ); + tolua_Error err; + if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) + { + return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->ExtractText(); + } + else + { + size_t len = 0; + const char * str = lua_tolstring(tolua_S, 1, &len); + if (str != NULL) + { + return AString(str, len); + } + } + return ""; +} + + + + + +static int tolua_LOG(lua_State * tolua_S) +{ + // If the param is a cCompositeChat, read the log level from it: + cMCLogger::eLogLevel LogLevel = cMCLogger::llRegular; + tolua_Error err; + if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) + { + LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->GetMessageType()); + } + + // Log the message: + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); return 0; } @@ -126,10 +161,9 @@ static int tolua_LOG(lua_State* tolua_S) -static int tolua_LOGINFO(lua_State* tolua_S) +static int tolua_LOGINFO(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 1 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llInfo); return 0; } @@ -137,10 +171,9 @@ static int tolua_LOGINFO(lua_State* tolua_S) -static int tolua_LOGWARN(lua_State* tolua_S) +static int tolua_LOGWARN(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 2 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llWarning); return 0; } @@ -148,10 +181,9 @@ static int tolua_LOGWARN(lua_State* tolua_S) -static int tolua_LOGERROR(lua_State* tolua_S) +static int tolua_LOGERROR(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 3 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llError); return 0; } @@ -159,6 +191,50 @@ static int tolua_LOGERROR(lua_State* tolua_S) +static int tolua_Base64Encode(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamString(1) || + !L.CheckParamEnd(2) + ) + { + return 0; + } + + AString Src; + L.GetStackValue(1, Src); + AString res = Base64Encode(Src); + L.Push(res); + return 1; +} + + + + + +static int tolua_Base64Decode(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamString(1) || + !L.CheckParamEnd(2) + ) + { + return 0; + } + + AString Src; + L.GetStackValue(1, Src); + AString res = Base64Decode(Src); + L.Push(res); + return 1; +} + + + + + cPluginLua * GetLuaPlugin(lua_State * L) { // Get the plugin identification out of LuaState: @@ -2838,6 +2914,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode); + tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); tolua_beginmodule(tolua_S, "cFile"); tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index e6594947e..f38e26267 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -5,4 +5,4 @@ class ManualBindings { public: static void Bind( lua_State* tolua_S ); -};
\ No newline at end of file +}; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 7e69e0f4b..dcc816839 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -5,7 +5,11 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#ifdef __APPLE__ +#define LUA_USE_MACOSX +#else #define LUA_USE_POSIX +#endif #include "PluginLua.h" #include "../CommandOutput.h" @@ -14,6 +18,7 @@ extern "C" #include "lua/src/lualib.h" } +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp index 3b71d553c..bf45405ba 100644 --- a/src/Bindings/WebPlugin.cpp +++ b/src/Bindings/WebPlugin.cpp @@ -110,4 +110,4 @@ AString cWebPlugin::SafeString( const AString & a_String ) RetVal.push_back( c ); } return RetVal; -}
\ No newline at end of file +} diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 2b950378a..60e4f11e5 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -173,6 +173,40 @@ static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a +/** Combinator used for cBlockArea::msDifference merging */ +static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta)) + { + a_DstType = E_BLOCK_AIR; + a_DstMeta = 0; + } + else + { + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; + } +} + + + + + +/** Combinator used for cBlockArea::msMask merging */ +static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + // If the blocks are the same, keep the dest; otherwise replace with air + if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta)) + { + a_DstType = E_BLOCK_AIR; + a_DstMeta = 0; + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cBlockArea: @@ -709,6 +743,36 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R ); break; } // case msSpongePrint + + case msDifference: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z, + MergeCombinatorDifference + ); + break; + } // case msDifference + + case msMask: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z, + MergeCombinatorMask + ); + break; + } // case msMask default: { diff --git a/src/BlockArea.h b/src/BlockArea.h index d37f0d182..c48175b8c 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -52,6 +52,8 @@ public: msImprint, msLake, msSpongePrint, + msDifference, + msMask, } ; cBlockArea(void); @@ -152,6 +154,14 @@ public: +----------+--------+--------+ | A | sponge | A | Sponge is the NOP block | * | B | B | Everything else overwrites anything + + msMask: + Combines two areas, the blocks that are the same are kept, differing ones are reset to air + | area block | | + | this | Src | result | + +------+-------+--------+ + | A | A | A | Same blocks are kept + | A | non-A | air | Everything else is replaced with air */ void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy); diff --git a/src/BlockTracer.h b/src/BlockTracer.h index 40d80da1a..a18c8df4d 100644 --- a/src/BlockTracer.h +++ b/src/BlockTracer.h @@ -28,6 +28,9 @@ public: class cCallbacks abstract { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /** Called on each block encountered along the path, including the first block (path start) When this callback returns true, the tracing is aborted. */ diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 9f5f84be0..93a796ef7 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -18,11 +18,13 @@ public: { } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); } + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -31,27 +33,23 @@ public: ) override { a_BlockType = m_BlockType; - - int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3; - int RawMeta = a_BlockMeta >> 2; - - Direction++; - Direction %= 4; + NIBBLETYPE HighBits = a_BlockMeta & 0x0c; // Only highest two bits are preserved + int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3; switch (Direction) { - case 0: a_BlockMeta = 0x2 | RawMeta << 2; break; - case 1: a_BlockMeta = 0x3 | RawMeta << 2; break; - case 2: a_BlockMeta = 0x0 | RawMeta << 2; break; - case 3: a_BlockMeta = 0x1 | RawMeta << 2; break; + case 0: a_BlockMeta = 0x2 | HighBits; break; + case 1: a_BlockMeta = 0x3 | HighBits; break; + case 2: a_BlockMeta = 0x0 | HighBits; break; + case 3: a_BlockMeta = 0x1 | HighBits; break; default: { return false; } } - return true; } + virtual bool IsUseable() override { return true; diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 2e1032d2b..41b79b6c3 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -23,7 +23,7 @@ public: virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { - char Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); switch (a_Player->GetEquippedItem().m_ItemType) { case E_ITEM_WATER_BUCKET: diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index ffc2b3f8b..8606cf3f3 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" @@ -21,7 +21,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override { - MTRand rand; + cFastRandom rand; if (a_Meta == 0x7) { @@ -31,18 +31,18 @@ public: case E_BLOCK_CROPS: { a_Pickups.push_back(cItem(E_ITEM_WHEAT, 1, 0)); - a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 + a_Pickups.push_back(cItem(E_ITEM_SEEDS, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_CARROTS: { - a_Pickups.push_back(cItem(E_ITEM_CARROT, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 + a_Pickups.push_back(cItem(E_ITEM_CARROT, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_POTATOES: { - a_Pickups.push_back(cItem(E_ITEM_POTATO, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 - if (rand.randInt(20) == 0) + a_Pickups.push_back(cItem(E_ITEM_POTATO, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 + if (rand.NextInt(21) == 0) { // With a 5% chance, drop a poisonous potato as well a_Pickups.push_back(cItem(E_ITEM_POISONOUS_POTATO, 1, 0)); diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index a1ab74257..aa24b8668 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" @@ -44,12 +44,12 @@ public: } // Grass spreads to adjacent dirt blocks: - MTRand rand; // TODO: Replace with cFastRandom + cFastRandom rand; for (int i = 0; i < 2; i++) // Pick two blocks to grow to { - int OfsX = rand.randInt(2) - 1; // [-1 .. 1] - int OfsY = rand.randInt(4) - 3; // [-3 .. 1] - int OfsZ = rand.randInt(2) - 1; // [-1 .. 1] + int OfsX = rand.NextInt(3, a_RelX) - 1; // [-1 .. 1] + int OfsY = rand.NextInt(5, a_RelY) - 3; // [-3 .. 1] + int OfsZ = rand.NextInt(3, a_RelZ) - 1; // [-1 .. 1] BLOCKTYPE DestBlock; NIBBLETYPE DestMeta; diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index a25b87858..c8f158e7e 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -17,25 +17,27 @@ public: } /// Portal boundary and direction variables - int XZP, XZM, Dir; // For wont of a better name... + // 2014_03_30 _X: What are these used for? Why do we need extra variables? + int XZP, XZM; + NIBBLETYPE Dir; virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { /* PORTAL FINDING ALGORITH ======================= - -Get clicked base block - -Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered. - Uses this value as a reference (the 'ceiling') - -For both directions (if one fails, try the other), BASE (clicked) block: - -Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1) - -If a border was encountered, go the other direction and repeat above - -Write borders to XZP and XZM, write direction portal faces to Dir - -Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir + - Get clicked base block + - Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered. + Uses this value as a reference (the 'ceiling') + - For both directions (if one fails, try the other), BASE (clicked) block: + - Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1) + - If a border was encountered, go the other direction and repeat above + - Write borders to XZP and XZM, write direction portal faces to Dir + - Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir */ a_BlockY--; // Because we want the block below the fire - FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); // Brought to you by Aperture Science + FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); } virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index a6d3373c1..8af14686e 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -1,6 +1,6 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" #include "../World.h" #include "../BlockArea.h" @@ -37,16 +37,18 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - MTRand rand; + cFastRandom rand; // Only the first 2 bits contain the display information, the others are for growing - if (rand.randInt(5) == 0) + if (rand.NextInt(6) == 0) { a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 3)); } - if ((a_BlockMeta & 3) == E_META_SAPLING_APPLE) + + // 1 % chance of dropping an apple, if the leaves' type is Apple Leaves + if ((a_BlockMeta & 3) == E_META_LEAVES_APPLE) { - if (rand.rand(100) == 0) + if (rand.NextInt(101) == 0) { a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); } @@ -58,11 +60,10 @@ public: { cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - //0.5% chance of dropping an apple + // 0.5% chance of dropping an apple, if the leaves' type is Apple Leaves: NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - //check if Oak (0x1 and 0x2 bit not set) - MTRand rand; - if(!(Meta & 3) && rand.randInt(200) == 100) + cFastRandom rand; + if (((Meta & 3) == E_META_LEAVES_APPLE) && (rand.NextInt(201) == 100)) { cItems Drops; Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index 6aa01f986..acd1c88fb 100644 --- a/src/Blocks/BlockMobHead.h +++ b/src/Blocks/BlockMobHead.h @@ -22,14 +22,99 @@ public: a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0)); } - bool TrySpawnWither(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) { if (a_BlockY < 2) { return false; } + + class cCallback : public cMobHeadCallback + { + bool m_IsWither; + + virtual bool Item (cMobHeadEntity * a_MobHeadEntity) + { + m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER); + + return false; + } + + public: + cCallback () : m_IsWither(false) {} + + bool IsWither(void) const { return m_IsWither; } + + void Reset(void) { m_IsWither = false; } + } CallbackA, CallbackB; + + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA); + + if (!CallbackA.IsWither()) + { + return false; + } + + CallbackA.Reset(); + + BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ); + + if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND)) + { + return false; + } + + a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA); + a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB); + + BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ); + BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ); + + if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither()) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Block entities + a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + + // Spawn the wither: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + + return true; + } + + CallbackA.Reset(); + CallbackB.Reset(); - // TODO 2014-03-24 xdot + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA); + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB); + + Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1); + Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1); + + if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither()) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Block entities + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0); + + // Spawn the wither: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + + return true; + } return false; } @@ -62,20 +147,37 @@ public: } public: - cCallback (cPlayer * a_Player, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) : - m_Player(a_Player), + cCallback (cPlayer * a_CBPlayer, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) : + m_Player(a_CBPlayer), m_OldBlockMeta(a_OldBlockMeta), m_NewBlockMeta(a_NewBlockMeta) {} }; cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace)); - a_BlockMeta = a_BlockFace; + a_BlockMeta = (NIBBLETYPE)a_BlockFace; cWorld * World = (cWorld *) &a_WorldInterface; World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); - TrySpawnWither(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + if (a_BlockMeta == SKULL_TYPE_WITHER) + { + static const Vector3i Coords[] = + { + Vector3i( 0, 0, 0), + Vector3i( 1, 0, 0), + Vector3i(-1, 0, 0), + Vector3i( 0, 0, 1), + Vector3i( 0, 0, -1), + }; + for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i) + { + if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z)) + { + break; + } + } // for i - Coords[] + } } } ; diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 923180e19..812cf906f 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -2,14 +2,13 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" #include "../World.h" -/// Common class that takes care of carrots, potatoes and wheat class cBlockNetherWartHandler : public cBlockHandler { @@ -22,12 +21,12 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override { - MTRand rand; + cFastRandom rand; if (a_Meta == 0x7) { - // Is fully grown, drop the entire produce: - a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); + // Fully grown, drop the entire produce: + a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, (char)(1 + (rand.NextInt(3) + rand.NextInt(3))) / 2, 0)); } else { @@ -35,18 +34,20 @@ public: } } + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { - NIBBLETYPE Meta = a_Chunk.GetMeta (a_RelX, a_RelY, a_RelZ); - + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); if (Meta < 7) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta); } } + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { + // Needs to be placed on top of a Soulsand block: return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND)); } } ; diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 477707a91..ad78d290a 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -431,6 +431,7 @@ public: } break; } + default: break; } return true; } diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 3f0fef0c7..76f5ed0e7 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -72,6 +72,7 @@ public: a_BlockMeta = Meta & 0x7; break; } } + case BLOCK_FACE_NONE: return false; } // switch (a_BlockFace) // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 1072b7e71..09ff254a6 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -30,9 +30,7 @@ public: UNUSED(a_BlockY); UNUSED(a_BlockZ); UNUSED(a_CursorX); - UNUSED(a_CursorY); UNUSED(a_CursorZ); - UNUSED(a_BlockMeta); a_BlockType = m_BlockType; a_BlockMeta = RotationToMetaData(a_Player->GetYaw()); switch (a_BlockFace) @@ -51,10 +49,12 @@ public: } break; } + case BLOCK_FACE_NONE: return false; } return true; } + virtual const char * GetStepSound(void) override { if ( diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 705436345..b726a0901 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -17,9 +17,10 @@ public: { } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - int ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; + short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; a_Pickups.push_back(cItem(ItemType, 1, 0)); } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index e14218633..7bb9dc484 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -83,7 +83,7 @@ public: static const struct { int x, z; - int Bit; + NIBBLETYPE Bit; } Coords[] = { { 0, 1, 1}, // south, ZP @@ -91,7 +91,7 @@ public: { 0, -1, 4}, // north, ZM { 1, 0, 8}, // east, XP } ; - int res = 0; + NIBBLETYPE res = 0; for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType; @@ -197,14 +197,14 @@ public: virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override { // Bits 2 and 4 stay, bits 1 and 3 swap - return ((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); + return (NIBBLETYPE)((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); } virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override { // Bits 1 and 3 stay, bits 2 and 4 swap - return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); + return (NIBBLETYPE)((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); } } ; diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index a917ee70f..c70ef1070 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -112,8 +112,8 @@ cCompositeChat::cCompositeChat(void) : -cCompositeChat::cCompositeChat(const AString & a_ParseText) : - m_MessageType(mtCustom) +cCompositeChat::cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType) : + m_MessageType(a_MessageType) { ParseText(a_ParseText); } @@ -314,6 +314,58 @@ void cCompositeChat::UnderlineUrls(void) +AString cCompositeChat::ExtractText(void) const +{ + AString Msg; + for (cParts::const_iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr) + { + switch ((*itr)->m_PartType) + { + case ptText: + case ptClientTranslated: + case ptRunCommand: + case ptSuggestCommand: + { + Msg.append((*itr)->m_Text); + break; + } + case ptUrl: + { + Msg.append(((cUrlPart *)(*itr))->m_Url); + break; + } + } // switch (PartType) + } // for itr - m_Parts[] + return Msg; +} + + + + + +cMCLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) +{ + switch (a_MessageType) + { + case mtCustom: return cMCLogger::llRegular; + case mtFailure: return cMCLogger::llWarning; + case mtInformation: return cMCLogger::llInfo; + case mtSuccess: return cMCLogger::llRegular; + case mtWarning: return cMCLogger::llWarning; + case mtFatal: return cMCLogger::llError; + case mtDeath: return cMCLogger::llRegular; + case mtPrivateMessage: return cMCLogger::llRegular; + case mtJoin: return cMCLogger::llRegular; + case mtLeave: return cMCLogger::llRegular; + } + ASSERT(!"Unhandled MessageType"); + return cMCLogger::llError; +} + + + + + void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) { if (a_AddStyle.empty()) diff --git a/src/CompositeChat.h b/src/CompositeChat.h index 27319490d..5b9c5f612 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -117,7 +117,7 @@ public: /** Creates a new chat message and parses the text into parts. Recognizes "http:" and "https:" links and @color-codes. Uses ParseText() for the actual parsing. */ - cCompositeChat(const AString & a_ParseText); + cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom); ~cCompositeChat(); @@ -164,10 +164,19 @@ public: /** Returns the message type set previously by SetMessageType(). */ eMessageType GetMessageType(void) const { return m_MessageType; } + /** Returns the text from the parts that comprises the human-readable data. + Used for older protocols that don't support composite chat + and for console-logging. */ + AString ExtractText(void) const; + // tolua_end const cParts & GetParts(void) const { return m_Parts; } + /** Converts the MessageType to a LogLevel value. + Used by the logging bindings when logging a cCompositeChat object. */ + static cMCLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); + protected: /** All the parts that */ cParts m_Parts; diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index 94b24c5af..921252253 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -122,5 +122,3 @@ void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways) AddSpeed(ToAddSpeed); } - -
\ No newline at end of file diff --git a/src/Entities/Effects.h b/src/Entities/Effects.h index e7611847d..baf3302fb 100644 --- a/src/Entities/Effects.h +++ b/src/Entities/Effects.h @@ -27,4 +27,4 @@ enum ENUM_ENTITY_EFFECT E_EFFECT_ABSORPTION = 22, E_EFFECT_SATURATION = 23, } ; -// tolua_end
\ No newline at end of file +// tolua_end diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h index c1150bd03..e76274ac9 100644 --- a/src/Entities/ExpOrb.h +++ b/src/Entities/ExpOrb.h @@ -42,4 +42,4 @@ protected: /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ float m_Timer; -} ; // tolua_export
\ No newline at end of file +} ; // tolua_export diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h index f3b51d77b..547d503f1 100644 --- a/src/Entities/Floater.h +++ b/src/Entities/Floater.h @@ -43,4 +43,4 @@ protected: // Entity IDs int m_PlayerID; int m_AttachedMobID; -} ; // tolua_export
\ No newline at end of file +} ; // tolua_export diff --git a/src/Group.cpp b/src/Group.cpp index 5f1f25782..9c2467144 100644 --- a/src/Group.cpp +++ b/src/Group.cpp @@ -38,4 +38,4 @@ void cGroup::InheritFrom( cGroup* a_Group ) void cGroup::ClearPermission() { m_Permissions.clear(); -}
\ No newline at end of file +} diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h index 6430fbebf..866bed11d 100644 --- a/src/HTTPServer/EnvelopeParser.h +++ b/src/HTTPServer/EnvelopeParser.h @@ -19,6 +19,9 @@ public: class cCallbacks { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /// Called when a full header line is parsed virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0; } ; diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h index a554ca5a4..f2a509cb8 100644 --- a/src/HTTPServer/HTTPFormParser.h +++ b/src/HTTPServer/HTTPFormParser.h @@ -36,6 +36,9 @@ public: class cCallbacks { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /// Called when a new file part is encountered in the form data virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0; diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h index d853929ed..77695fe4a 100644 --- a/src/HTTPServer/MultipartParser.h +++ b/src/HTTPServer/MultipartParser.h @@ -22,6 +22,9 @@ public: class cCallbacks { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /// Called when a new part starts virtual void OnPartStart(void) = 0; diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index a28ec8e22..42f4ffc8f 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -39,12 +39,20 @@ public: public cBlockTracer::cCallbacks { public: - Vector3d Pos; - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + Vector3d m_Pos; + bool m_HasFound; + + cCallbacks(void) : + m_HasFound(false) { - if (a_BlockType != E_BLOCK_AIR) + } + + virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override + { + if (a_CBBlockType != E_BLOCK_AIR) { - Pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ); + m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); + m_HasFound = true; return true; } return false; @@ -57,15 +65,15 @@ public: Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); - double x = Callbacks.Pos.x; - double y = Callbacks.Pos.y; - double z = Callbacks.Pos.z; - - if ((x == 0) && (y == 0) && (z == 0)) + if (!Callbacks.m_HasFound) { return false; } + double x = Callbacks.m_Pos.x; + double y = Callbacks.m_Pos.y; + double z = Callbacks.m_Pos.z; + cBoat * Boat = new cBoat(x + 0.5, y + 1, z + 0.5); Boat->Initialize(a_World); diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp index 4f3e5dc0f..80fa7b173 100644 --- a/src/MCLogger.cpp +++ b/src/MCLogger.cpp @@ -93,25 +93,30 @@ void cMCLogger::InitLog(const AString & a_FileName) -void cMCLogger::LogSimple(const char* a_Text, int a_LogType /* = 0 */ ) +void cMCLogger::LogSimple(const char * a_Text, eLogLevel a_LogLevel) { - switch( a_LogType ) + switch (a_LogLevel) { - case 0: + case llRegular: + { LOG("%s", a_Text); break; - case 1: + } + case llInfo: + { LOGINFO("%s", a_Text); break; - case 2: + } + case llWarning: + { LOGWARN("%s", a_Text); break; - case 3: + } + case llError: + { LOGERROR("%s", a_Text); break; - default: - LOG("(#%d#: %s", a_LogType, a_Text); - break; + } } } diff --git a/src/MCLogger.h b/src/MCLogger.h index 996e60329..c0150c124 100644 --- a/src/MCLogger.h +++ b/src/MCLogger.h @@ -10,25 +10,36 @@ class cLog; -class cMCLogger // tolua_export -{ // tolua_export -public: // tolua_export - /// Creates a logger with the default filename, "logs/LOG_<timestamp>.log" +// tolua_begin +class cMCLogger +{ +public: + enum eLogLevel + { + llRegular, + llInfo, + llWarning, + llError, + }; + // tolua_end + + /** Creates a logger with the default filename, "logs/LOG_<timestamp>.log" */ cMCLogger(void); - /// Creates a logger with the specified filename inside "logs" folder + /** Creates a logger with the specified filename inside "logs" folder */ cMCLogger(const AString & a_FileName); // tolua_export ~cMCLogger(); // tolua_export - void Log(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Info(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Warn(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Error(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Log (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Info (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Warn (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Error(const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export + /** Logs the simple text message at the specified log level. */ + void LogSimple(const char * a_Text, eLogLevel a_LogLevel = llRegular); // tolua_export - static cMCLogger* GetInstance(); + static cMCLogger * GetInstance(); private: enum eColorScheme { diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index ac42cf40b..84ff8929b 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -53,4 +53,4 @@ void cBlaze::Attack(float a_Dt) m_AttackInterval = 0.0; // ToDo: Shoot 3 fireballs instead of 1. } -}
\ No newline at end of file +} diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h index cdb3a1306..5970451c7 100644 --- a/src/Mobs/Blaze.h +++ b/src/Mobs/Blaze.h @@ -20,7 +20,3 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void Attack(float a_Dt) override; } ; - - - - diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 47fcdbb26..1685f40c5 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -88,4 +88,4 @@ void cSkeleton::Attack(float a_Dt) m_World->BroadcastSpawnEntity(*Arrow); m_AttackInterval = 0.0; } -}
\ No newline at end of file +} diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index 0e42194ac..8f5d28b68 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -13,8 +13,27 @@ cWither::cWither(void) : m_InvulnerableTicks(220) { SetMaxHealth(300); +} + + + + + +bool cWither::IsArmored(void) const +{ + return GetHealth() <= (GetMaxHealth() / 2); +} + + + + +bool cWither::Initialize(cWorld * a_World) +{ + // Set health before BroadcastSpawnEntity() SetHealth(GetMaxHealth() / 3); + + return super::Initialize(a_World); } @@ -33,6 +52,11 @@ void cWither::DoTakeDamage(TakeDamageInfo & a_TDI) return; } + if (IsArmored() && (a_TDI.DamageType == dtRangedAttack)) + { + return; + } + super::DoTakeDamage(a_TDI); } @@ -60,6 +84,8 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk) Heal(10); } } + + m_World->BroadcastEntityMetadata(*this); } diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index d09e3607a..bc78bfaad 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -20,8 +20,12 @@ public: unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; } void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; } + + /** Returns whether the wither is invulnerable to arrows. */ + bool IsArmored(void) const; // cEntity overrides + virtual bool Initialize(cWorld * a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp index 2e05f1df1..6072b6ac6 100644 --- a/src/OSSupport/Errors.cpp +++ b/src/OSSupport/Errors.cpp @@ -22,7 +22,7 @@ AString GetOSErrorString( int a_ErrNo ) // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r(): - #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r() + #if !defined(__APPLE__) && ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r() char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) ); if( res != NULL ) diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 17070030f..7f0f0ad2f 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -152,7 +152,7 @@ int cFile::Read (void * iBuffer, int iNumBytes) return -1; } - return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count + return (int)fread(iBuffer, 1, (size_t)iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count } @@ -168,7 +168,7 @@ int cFile::Write(const void * iBuffer, int iNumBytes) return -1; } - int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count + int res = (int)fwrite(iBuffer, 1, (size_t)iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count return res; } @@ -189,7 +189,7 @@ int cFile::Seek (int iPosition) { return -1; } - return ftell(m_File); + return (int)ftell(m_File); } @@ -206,7 +206,7 @@ int cFile::Tell (void) const return -1; } - return ftell(m_File); + return (int)ftell(m_File); } @@ -222,7 +222,7 @@ int cFile::GetSize(void) const return -1; } - int CurPos = ftell(m_File); + int CurPos = Tell(); if (CurPos < 0) { return -1; @@ -231,8 +231,8 @@ int cFile::GetSize(void) const { return -1; } - int res = ftell(m_File); - if (fseek(m_File, CurPos, SEEK_SET) != 0) + int res = Tell(); + if (fseek(m_File, (long)CurPos, SEEK_SET) != 0) { return -1; } @@ -255,7 +255,7 @@ int cFile::ReadRestOfFile(AString & a_Contents) int DataSize = GetSize() - Tell(); // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly - a_Contents.assign(DataSize, '\0'); + a_Contents.assign((size_t)DataSize, '\0'); return Read((void *)a_Contents.data(), DataSize); } @@ -350,7 +350,7 @@ int cFile::GetSize(const AString & a_FileName) struct stat st; if (stat(a_FileName.c_str(), &st) == 0) { - return st.st_size; + return (int)st.st_size; } return -1; } @@ -456,7 +456,7 @@ int cFile::Printf(const char * a_Fmt, ...) va_start(args, a_Fmt); AppendVPrintf(buf, a_Fmt, args); va_end(args); - return Write(buf.c_str(), buf.length()); + return Write(buf.c_str(), (int)buf.length()); } diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index b13e519e0..7a8433f4f 100644 --- a/src/OSSupport/GZipFile.cpp +++ b/src/OSSupport/GZipFile.cpp @@ -78,7 +78,7 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents) while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0) { TotalBytes += NumBytesRead; - a_Contents.append(Buffer, NumBytesRead); + a_Contents.append(Buffer, (size_t)NumBytesRead); } // NumBytesRead is < 0 on error return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead; @@ -102,7 +102,7 @@ bool cGZipFile::Write(const char * a_Contents, int a_Size) return false; } - return (gzwrite(m_File, a_Contents, a_Size) != 0); + return (gzwrite(m_File, a_Contents, (unsigned int)a_Size) != 0); } diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h index 5298c15da..0ec0adf9d 100644 --- a/src/OSSupport/Sleep.h +++ b/src/OSSupport/Sleep.h @@ -4,4 +4,4 @@ class cSleep { public: static void MilliSleep( unsigned int a_MilliSeconds ); -};
\ No newline at end of file +}; diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h index 3c9316424..4153b2427 100644 --- a/src/OSSupport/Thread.h +++ b/src/OSSupport/Thread.h @@ -23,4 +23,4 @@ private: cEvent* m_StopEvent; AString m_ThreadName; -};
\ No newline at end of file +}; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 69f4934d8..fe6280218 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -239,32 +239,11 @@ void cProtocol125::SendChat(const AString & a_Message) void cProtocol125::SendChat(const cCompositeChat & a_Message) { // This version doesn't support composite messages, just extract each part's text and use it: - AString Msg; - const cCompositeChat::cParts & Parts = a_Message.GetParts(); - for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr) - { - switch ((*itr)->m_PartType) - { - case cCompositeChat::ptText: - case cCompositeChat::ptClientTranslated: - case cCompositeChat::ptRunCommand: - case cCompositeChat::ptSuggestCommand: - { - Msg.append((*itr)->m_Text); - break; - } - case cCompositeChat::ptUrl: - { - Msg.append(((cCompositeChat::cUrlPart *)(*itr))->m_Url); - break; - } - } // switch (PartType) - } // for itr - Parts[] // Send the message: cCSLock Lock(m_CSPacket); WriteByte (PACKET_CHAT); - WriteString(Msg); + WriteString(a_Message.ExtractText()); Flush(); } @@ -1972,6 +1951,14 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything break; } + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: case cMonster::mtMagmaCube: { diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 721ed349e..c678fc9a0 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -2535,6 +2535,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteByte(Frame.GetRotation()); break; } + default: break; } } @@ -2659,6 +2660,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); break; } + + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: { diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index 5b9a3bb0a..2a85649a1 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -53,7 +53,7 @@ int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed -int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed) +int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed) { // Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2() @@ -83,6 +83,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed { // Some data has been compressed. Consume the buffer and continue compressing a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); if (strm.avail_in == 0) { @@ -116,7 +117,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed -extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed) +extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed) { // Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib @@ -139,13 +140,14 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U for (;;) { - res = inflate(&strm, Z_FINISH); + res = inflate(&strm, Z_NO_FLUSH); switch (res) { case Z_OK: { // Some data has been uncompressed. Consume the buffer and continue uncompressing a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); if (strm.avail_in == 0) { diff --git a/src/StringCompression.h b/src/StringCompression.h index 3f4e12d2d..c3a9eca91 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -16,10 +16,10 @@ extern int CompressString(const char * a_Data, int a_Length, AString & a_Compres extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize); /// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib -extern int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed); +extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed); /// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib -extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed); +extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed); diff --git a/src/StringUtils.h b/src/StringUtils.h index 4feff7553..da395e5b5 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -79,10 +79,10 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway /// Decodes a Base64-encoded string into the raw data -extern AString Base64Decode(const AString & a_Base64String); +extern AString Base64Decode(const AString & a_Base64String); // Exported manually due to embedded NULs and extra parameter /// Encodes a string into Base64 -extern AString Base64Encode(const AString & a_Input); +extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter /// Reads two bytes from the specified memory location and interprets them as BigEndian short extern short GetBEShort(const char * a_Mem); diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h index 5b87bafdb..cbc544a14 100644 --- a/src/WorldStorage/FireworksSerializer.h +++ b/src/WorldStorage/FireworksSerializer.h @@ -89,4 +89,4 @@ public: short m_FlightTimeInTicks; std::vector<int> m_Colours; std::vector<int> m_FadeColours; -};
\ No newline at end of file +}; diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp index d8531d965..9d594a084 100644 --- a/src/WorldStorage/SchematicFileSerializer.cpp +++ b/src/WorldStorage/SchematicFileSerializer.cpp @@ -14,6 +14,39 @@ +#ifdef SELF_TEST + +static class cSchematicStringSelfTest +{ +public: + cSchematicStringSelfTest(void) + { + cBlockArea ba; + ba.Create(21, 256, 21); + ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1); + AString Schematic; + if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic)) + { + assert_test(!"Schematic failed to save!"); + } + cBlockArea ba2; + if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic)) + { + assert_test(!"Schematic failed to load!"); + } + } +} g_SelfTest; + +#endif + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSchematicFileSerializer: + bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName) { // Un-GZip the contents: |