diff options
33 files changed, 662 insertions, 97 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index d388d15dd..26537918e 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1713,7 +1713,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ForceExecuteCommand = { Params = "{{cPlayer|Player}}, CommandStr", Return = "bool", Notes = "Same as ExecuteCommand, but doesn't check permissions" }, ForEachCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function(Command, Permission, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, ForEachConsoleCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindConsoleCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function (Command, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, - Get = { Params = "", Return = "cPluginManager", Notes = "Returns the single instance of the plugin manager" }, + Get = { Params = "", Return = "cPluginManager", Notes = "(STATIC) Returns the single instance of the plugin manager" }, GetAllPlugins = { Params = "", Return = "table", Notes = "Returns a table (dictionary) of all plugins, [name => {{cPlugin}}] pairing." }, GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" }, GetCurrentPlugin = { Params = "", Return = "{{cPlugin}}", Notes = "Returns the {{cPlugin}} object for the calling plugin. This is the same object that the Initialize function receives as the argument." }, diff --git a/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html b/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html index 50e39d533..0e07cebdf 100644 --- a/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html +++ b/MCServer/Plugins/APIDump/Writing-a-MCServer-plugin.html @@ -84,7 +84,7 @@ end To register a hook, insert the following code template into the "-- Hooks" area in the previous code example. </p> <pre class="prettyprint lang-lua"> -cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled) +cPluginManager:AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled) </pre> <p> What does this code do? @@ -102,7 +102,7 @@ function Initialize(Plugin) Plugin:SetName("DerpyPlugin") Plugin:SetVersion(1) - cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving) + cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving) local PluginManager = cPluginManager:Get() -- Command bindings @@ -200,7 +200,7 @@ function Initialize(Plugin) local PluginManager = cPluginManager:Get() PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player"); - cPluginManager.AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup) + cPluginManager:AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup) LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) return true diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index b3a95eb22..bd509dcb6 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -1177,7 +1177,7 @@ function WriteHtmlHook(a_Hook, a_HookNav) f:write("</table>\n<p>" .. (a_Hook.Returns or "") .. "</p>\n\n"); f:write([[<hr /><h1>Code examples</h1><h2>Registering the callback</h2>]]); f:write("<pre class=\"prettyprint lang-lua\">\n"); - f:write([[cPluginManager.AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]); + f:write([[cPluginManager:AddHook(cPluginManager.]] .. a_Hook.Name .. ", My" .. a_Hook.DefaultFnName .. [[);]]); f:write("</pre>\n\n"); local Examples = a_Hook.CodeExamples or {}; for i, example in ipairs(Examples) do diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 8f2fa3682..c769edc3e 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -963,3 +963,22 @@ end + +-- Test the hook adding formats in #121 and #401 +local function DoNothing() +end + +LOG("Trying cPluginManager:AddHook()"); +cPluginManager:AddHook(cPluginManager.HOOK_CHAT, DoNothing); + +LOG("Trying cPluginManager.AddHook()"); +cPluginManager.AddHook(cPluginManager.HOOK_CHAT, DoNothing); + +LOG("Trying cPluginManager:Get():AddHook()"); +cPluginManager:Get():AddHook(cPluginManager.HOOK_CHAT, DoNothing); + +LOG("Trying cPluginManager:Get():AddHook(Plugin, Hook)"); +cPluginManager:Get():AddHook(cPluginManager:GetCurrentPlugin(), cPluginManager.HOOK_CHAT); + +LOG("Trying cPluginManager.AddHook(Plugin, Hook)"); +cPluginManager.AddHook(cPluginManager:GetCurrentPlugin(), cPluginManager.HOOK_CHAT); diff --git a/MCServer/Plugins/InfoDump.deproj b/MCServer/Plugins/InfoDump.deproj new file mode 100644 index 000000000..30003c36d --- /dev/null +++ b/MCServer/Plugins/InfoDump.deproj @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<project> + <file> + <filename>InfoDump.lua</filename> + </file> +</project> diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua new file mode 100644 index 000000000..df47d566b --- /dev/null +++ b/MCServer/Plugins/InfoDump.lua @@ -0,0 +1,361 @@ +#!/usr/bin/lua + +-- InfoDump.lua + +-- Goes through all subfolders, loads Info.lua and dumps its g_PluginInfo into various text formats +-- This is used for generating plugin documentation for the forum and for GitHub's INFO.md files + +-- This script requires LuaRocks with LFS installed, instructions are printed when this is not present. + + + + + +-- Check Lua version. We use 5.1-specific construct when loading the plugin info, 5.2 is not compatible! +if (_VERSION ~= "Lua 5.1") then + print("Unsupported Lua version. This script requires Lua version 5.1, this Lua is version " .. (_VERSION or "<nil>")); + return; +end + +-- Try to load lfs, do not abort if not found +local lfs, err = pcall( + function() + return require("lfs") + end +); + +-- Rather, print a nice message with instructions: +if not(lfs) then + print([[ +Cannot load LuaFileSystem +Install it through luarocks by executing the following command: + sudo luarocks install luafilesystem + +If you don't have luarocks installed, you need to install them using your OS's package manager, usually: + sudo apt-get install luarocks +On windows, a binary distribution can be downloaded from the LuaRocks homepage, http://luarocks.org/en/Download +]]); + + print("Original error text: ", err); + return; +end + +-- We now know that LFS is present, get it normally: +lfs = require("lfs"); + + + + + + +--- Replaces generic formatting with forum-specific formatting +-- Also removes the single line-ends +local function ForumizeString(a_Str) + assert(type(a_Str) == "string"); + + -- Remove the indentation, unless in the code tag: + -- Only one code or /code tag per line is supported! + local IsInCode = false; + local function RemoveIndentIfNotInCode(s) + if (IsInCode) then + -- we're in code section, check if this line terminates it + IsInCode = (s:find("{%%/code}") ~= nil); + return s .. "\n"; + else + -- we're not in code section, check if this line starts it + IsInCode = (s:find("{%%code}") ~= nil); + return s:gsub("^%s*", "") .. "\n"; + end + end + a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode); + + -- Replace multiple line ends with {%p} and single line ends with a space, + -- so that manual word-wrap in the Info.lua file doesn't wrap in the forum. + a_Str = a_Str:gsub("\n\n", "{%%p}"); + a_Str = a_Str:gsub("\n", " "); + + -- Replace the generic formatting: + a_Str = a_Str:gsub("{%%p}", "\n\n"); + a_Str = a_Str:gsub("{%%b}", "[b]"):gsub("{%%/b}", "[/b]"); + a_Str = a_Str:gsub("{%%i}", "[i]"):gsub("{%%/i}", "[/i]"); + a_Str = a_Str:gsub("{%%list}", "[list]"):gsub("{%%/list}", "[/list]"); + a_Str = a_Str:gsub("{%%li}", "[*]"):gsub("{%%/li}", ""); + -- TODO: Other formatting + + return a_Str; +end + + + + + +--- Builds an array of categories, each containing all the commands belonging to the category, +-- and the category description, if available. +-- Returns the array table, each item has the following format: +-- { Name = "CategoryName", Description = "CategoryDescription", Commands = {{CommandString = "/cmd verb", Info = {...}}, ...}} +local function BuildCategories(a_PluginInfo) + -- The returned result + -- This will contain both an array and a dict of the categories, to allow fast search + local res = {}; + + -- For each command add a reference to it into all of its categories: + local function AddCommands(a_CmdPrefix, a_Commands) + for cmd, info in pairs(a_Commands) do + local NewCmd = + { + CommandString = a_CmdPrefix .. cmd, + Info = info, + } + + if ((info.HelpString ~= nil) and (info.HelpString ~= "")) then + -- Add to each specified category: + local Category = info.Category; + if (type(Category) == "string") then + Category = {Category}; + end + for idx, cat in ipairs(Category or {""}) do + local CatEntry = res[cat]; + if (CatEntry == nil) then + -- First time we came across this category, create it: + local NewCat = {Name = cat, Description = "", Commands = {NewCmd}}; + table.insert(res, NewCat); + res[cat] = NewCat; + else + -- We already have this category, just add the command to its list of commands: + table.insert(CatEntry.Commands, NewCmd); + end + end -- for idx, cat - Category[] + end -- if (HelpString valid) + + -- Recurse all subcommands: + if (info.Subcommands ~= nil) then + AddCommands(a_CmdPrefix .. cmd .. " ", info.Subcommands); + end + end -- for cmd, info - a_Commands[] + end -- AddCommands() + + AddCommands("", a_PluginInfo.Commands); + + -- Assign descriptions to categories: + for name, desc in pairs(a_PluginInfo.Categories or {}) do + local CatEntry = res[name]; + if (CatEntry ~= nil) then + -- The result has this category, add the description: + CatEntry.Description = desc.Description; + end + end + + -- Alpha-sort each category's command list: + for idx, cat in ipairs(res) do + table.sort(cat.Commands, + function (cmd1, cmd2) + return (string.lower(cmd1.CommandString) < string.lower(cmd2.CommandString)); + end + ); + end + + return res; +end + + + + + +--- Writes the specified command detailed help array to the output file, in the forum dump format +local function WriteCommandParameterCombinationsForum(a_CmdString, a_ParameterCombinations, f) + assert(type(a_CmdString) == "string"); + assert(type(a_ParameterCombinations) == "table"); + assert(f ~= nil); + + if (#a_ParameterCombinations == 0) then + -- No explicit parameter combinations to write + return; + end + + f:write("The following parameter combinations are recognized:\n"); + for idx, combination in ipairs(a_ParameterCombinations) do + f:write("[color=blue]", a_CmdString, "[/color] [color=green]", combination.Params, "[/color]"); + if (combination.Help ~= nil) then + f:write(" - ", ForumizeString(combination.Help)); + end + if (combination.Permission ~= nil) then + f:write(" (Requires permission '[color=red]", combination.Permission, "[/color]')"); + end + f:write("\n"); + end +end + + + + + +--- Writes all commands in the specified category to the output file, in the forum dump format +local function WriteCommandsCategoryForum(a_Category, f) + -- Write category name: + local CategoryName = a_Category.Name; + if (CategoryName == "") then + CategoryName = "General"; + end + f:write("\n[size=Large]", ForumizeString(a_Category.DisplayName or CategoryName), "[/size]\n"); + + -- Write description: + if (a_Category.Description ~= "") then + f:write(ForumizeString(a_Category.Description), "\n"); + end + + -- Write commands: + f:write("\n[list]"); + for idx2, cmd in ipairs(a_Category.Commands) do + f:write("\n[b]", cmd.CommandString, "[/b] - ", ForumizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n"); + if (cmd.Info.Permission ~= nil) then + f:write("Permission required: [color=red]", cmd.Info.Permission, "[/color]\n"); + end + if (cmd.Info.DetailedDescription ~= nil) then + f:write(cmd.Info.DetailedDescription); + end + if (cmd.Info.ParameterCombinations ~= nil) then + WriteCommandParameterCombinationsForum(cmd.CommandString, cmd.Info.ParameterCombinations, f); + end + end + f:write("[/list]\n\n") +end + + + + + +local function DumpCommandsForum(a_PluginInfo, f) + -- Copy all Categories from a dictionary into an array: + local Categories = BuildCategories(a_PluginInfo); + + -- Sort the categories by name: + table.sort(Categories, + function(cat1, cat2) + return (string.lower(cat1.Name) < string.lower(cat2.Name)); + end + ); + + if (#Categories == 0) then + return; + end + + f:write("\n[size=X-Large]Commands[/size]\n"); + + -- Dump per-category commands: + for idx, cat in ipairs(Categories) do + WriteCommandsCategoryForum(cat, f); + end +end + + + + + +local function DumpAdditionalInfoForum(a_PluginInfo, f) + local AInfo = a_PluginInfo.AdditionalInfo; + if ((AInfo == nil) or (type(AInfo) ~= "table")) then + -- There is no AdditionalInfo in a_PluginInfo + return; + end + + for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do + if ((info.Title ~= nil) and (info.Contents ~= nil)) then + f:write("\n[size=X-Large]", ForumizeString(info.Title), "[/size]\n"); + f:write(ForumizeString(info.Contents), "\n"); + end + end +end + + + + + +local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo) + -- Open the output file: + local f, msg = io.open(a_PluginInfo.Name .. "_forum.txt", "w"); + if (f == nil) then + print("\tCannot dump forum info for plugin " .. a_PluginFolder .. ": " .. msg); + return; + end + + -- Write the description: + f:write(ForumizeString(a_PluginInfo.Description), "\n"); + DumpAdditionalInfoForum(a_PluginInfo, f); + DumpCommandsForum(a_PluginInfo, f); + + f:close(); +end + + + + + +local function DumpPluginInfoGitHub() + -- TODO +end + + + + + +--- Tries to load the g_PluginInfo from the plugin's Info.lua file +-- Returns the g_PluginInfo table on success, or nil and error message on failure +local function LoadPluginInfo(a_FolderName) + -- Check if the Info file is present at all: + local Attribs = lfs.attributes(a_FolderName .. "/Info.lua"); + if ((Attribs == nil) or (Attribs.mode ~= "file")) then + return nil; + end + + -- Load and compile the Info file: + local cfg, err = loadfile(a_FolderName .. "/Info.lua"); + if (cfg == nil) then + return nil, "Cannot open 'Info.lua': " .. err; + end + + -- Execute the loaded file in a sandbox: + -- This is Lua-5.1-specific and won't work in Lua 5.2! + local Sandbox = {}; + setfenv(cfg, Sandbox); + cfg(); + if (Sandbox.g_PluginInfo == nil) then + return nil, "Info.lua doesn't contain the g_PluginInfo declaration"; + end + return Sandbox.g_PluginInfo; +end + + + + + +local function ProcessPluginFolder(a_FolderName) + local PluginInfo, Msg = LoadPluginInfo(a_FolderName); + if (PluginInfo == nil) then + if (Msg ~= nil) then + print("\tCannot load Info.lua: " .. Msg); + end + return; + end + DumpPluginInfoForum(a_FolderName, PluginInfo); +end + + + + + +print("Processing plugin subfolders:"); +for fnam in lfs.dir(".") do + if ((fnam ~= ".") and (fnam ~= "..")) then + local Attributes = lfs.attributes(fnam); + if (Attributes ~= nil) then + if (Attributes.mode == "directory") then + print(fnam); + ProcessPluginFolder(fnam); + end + end + end +end + + + + @@ -1,6 +1,8 @@ MCServer ======== +**Current Protocol Supported:** Minecraft v1.2 -> v1.7 + MCServer is a performant C++ Minecraft server designed for use in memory and cpu-limited places, or just to make regular server perform better. MCServer can run on PCs, Macs, and *nix. This includes android phones and tablets as well as Raspberry Pis. @@ -26,7 +28,7 @@ MCServer is licensed under the Apache license V2, and we welcome anybody to fork Other Stuff ----------- -For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [wiki](http://mc-server.org/wiki/). +For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [wiki](http://wiki.mc-server.org/). Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) diff --git a/VC2008/CryptoPP.vcproj b/VC2008/CryptoPP.vcproj index a818e9aa1..f44729d8a 100644 --- a/VC2008/CryptoPP.vcproj +++ b/VC2008/CryptoPP.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" - Version="9,00" + Version="9.00" Name="CryptoPP" ProjectGUID="{3423EC9A-52E4-4A4D-9753-EDEBC38785EF}" RootNamespace="cryptlib" @@ -60,6 +60,7 @@ WarningLevel="3" SuppressStartupBanner="true" DebugInformationFormat="3" + DisableSpecificWarnings="4702" /> <Tool Name="VCManagedResourceCompilerTool" diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 491e7740e..a017b5a25 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1579,6 +1579,10 @@ > </File> <File + RelativePath="..\src\OSSupport\Queue.h" + > + </File> + <File RelativePath="..\src\OSSupport\Semaphore.cpp" > </File> diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 2e19c2581..64f542880 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -1137,16 +1137,17 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) { /* Function signatures: - cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) -- (1) recommended - cPluginManager:Get():AddHook(HOOK_TYPE, CallbackFunction) -- (2) accepted silently - cPluginManager:Get():AddHook(Plugin, HOOK_TYPE) -- (3) old style (#121), accepted but complained about - cPluginManager.AddHook(Plugin, HOOK_TYPE) -- (4) old style (#121) mangled, accepted but complained about + cPluginManager:AddHook(HOOK_TYPE, CallbackFunction) -- (1) recommended + cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) -- (2) accepted silently (#401 deprecates this) + cPluginManager:Get():AddHook(HOOK_TYPE, CallbackFunction) -- (3) accepted silently + cPluginManager:Get():AddHook(Plugin, HOOK_TYPE) -- (4) old style (#121), accepted but complained about in the console + cPluginManager.AddHook(Plugin, HOOK_TYPE) -- (5) old style (#121) mangled, accepted but complained about in the console */ cLuaState S(tolua_S); cPluginManager * PlgMgr = cPluginManager::Get(); - // If the first param is a cPluginManager, use it instead of the global one: + // If the first param is a cPluginManager instance, use it instead of the global one: int ParamIdx = 1; tolua_Error err; if (tolua_isusertype(S, 1, "cPluginManager", 0, &err)) @@ -1161,6 +1162,12 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) } ParamIdx += 1; } + else if (tolua_isusertable(S, 1, "cPluginManager", 0, &err)) + { + LOGD("AddHook recommended style"); + // Style 1, use the global PlgMgr, but increment ParamIdx + ParamIdx++; + } if (lua_isnumber(S, ParamIdx) && lua_isfunction(S, ParamIdx + 1)) { @@ -1177,7 +1184,7 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) AString ParamDesc; Printf(ParamDesc, "%s, %s, %s", S.GetTypeText(1).c_str(), S.GetTypeText(2).c_str(), S.GetTypeText(3).c_str()); - LOGWARNING("cPluginManager.AddHook(): bad parameters. Expected HOOK_TYPE and CallbackFunction, got %s. Hook not added.", ParamDesc.c_str()); + LOGWARNING("cPluginManager:AddHook(): bad parameters. Expected HOOK_TYPE and CallbackFunction, got %s. Hook not added.", ParamDesc.c_str()); S.LogStackTrace(); return 0; } diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index b1409f5cc..f15553968 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -70,8 +70,8 @@ void cFurnaceEntity::UsedBy(cPlayer * a_Player) if (a_Player->GetWindow() != Window) { a_Player->OpenWindow(Window); - BroadcastProgress(PROGRESSBAR_FUEL, m_LastProgressFuel); - BroadcastProgress(PROGRESSBAR_SMELTING, m_LastProgressCook); + BroadcastProgress(PROGRESSBAR_FUEL, (short)m_LastProgressFuel); + BroadcastProgress(PROGRESSBAR_SMELTING, (short)m_LastProgressCook); } } } @@ -445,14 +445,14 @@ void cFurnaceEntity::UpdateProgressBars(void) int CurFuel = (m_FuelBurnTime > 0) ? (200 - 200 * m_TimeBurned / m_FuelBurnTime) : 0; if ((CurFuel / 8) != (m_LastProgressFuel / 8)) { - BroadcastProgress(PROGRESSBAR_FUEL, CurFuel); + BroadcastProgress(PROGRESSBAR_FUEL, (short)CurFuel); m_LastProgressFuel = CurFuel; } int CurCook = (m_NeedCookTime > 0) ? (200 * m_TimeCooked / m_NeedCookTime) : 0; if ((CurCook / 8) != (m_LastProgressCook / 8)) { - BroadcastProgress(PROGRESSBAR_SMELTING, CurCook); + BroadcastProgress(PROGRESSBAR_SMELTING, (short)CurCook); m_LastProgressCook = CurCook; } } diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index 0aca3209f..eac59e74d 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -488,7 +488,6 @@ bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, int a_BlockX, int a_Blo // Feed the fuel slot of the furnace return MoveItemsToSlot(*Furnace, cFurnaceEntity::fsFuel); } - return false; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd06798ff..853138769 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,7 +66,7 @@ set(EXECUTABLE MCServer) add_executable(${EXECUTABLE} ${SOURCE}) -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/MCServer) +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) if (MSVC) # MSVC generator adds a "Debug" or "Release" postfixes to the EXECUTABLE_OUTPUT_PATH, we need to cancel them: diff --git a/src/Globals.h b/src/Globals.h index 58badf4dd..1765c53d8 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -14,7 +14,21 @@ #pragma warning(disable:4481) // Disable some warnings that we don't care about: - #pragma warning(disable:4100) + #pragma warning(disable:4100) // Unreferenced formal parameter + + // Useful warnings from warning level 4: + #pragma warning(3 : 4189) // Local variable is initialized but not referenced + #pragma warning(3 : 4702) // Unreachable code + #pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch + #pragma warning(3 : 4389) // Signed/unsigned mismatch + #pragma warning(3 : 4701) // Potentially unitialized local variable used + #pragma warning(3 : 4310) // Cast truncates constant value + #pragma warning(3 : 4505) // Unreferenced local function has been removed + #pragma warning(3 : 4127) // Conditional expression is constant + #pragma warning(3 : 4706) // Assignment within conditional expression + + // 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places + // #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data #define OBSOLETE __declspec(deprecated) @@ -192,7 +206,7 @@ typedef unsigned short UInt16; #ifdef _DEBUG #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) ) #else - #define ASSERT(x) ((void)0) + #define ASSERT(x) ((void)(x)) #endif // Pretty much the same as ASSERT() but stays in Release builds diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index 68afdfc11..3d30ab177 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -57,7 +57,7 @@ void cHTTPConnection::SendNeedAuth(const AString & a_Realm) void cHTTPConnection::Send(const cHTTPResponse & a_Response) { - ASSERT(m_State = wcsRecvIdle); + ASSERT(m_State == wcsRecvIdle); a_Response.AppendToData(m_OutgoingData); m_State = wcsSendingResp; m_HTTPServer.NotifyConnectionWrite(*this); diff --git a/src/HTTPServer/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp index 01c68881a..e661ea6f9 100644 --- a/src/HTTPServer/HTTPFormParser.cpp +++ b/src/HTTPServer/HTTPFormParser.cpp @@ -133,7 +133,6 @@ bool cHTTPFormParser::HasFormData(const cHTTPRequest & a_Request) (a_Request.GetURL().find('?') != AString::npos) ) ); - return false; } diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp index fd56f6b24..9ea8594ae 100644 --- a/src/HTTPServer/NameValueParser.cpp +++ b/src/HTTPServer/NameValueParser.cpp @@ -253,7 +253,6 @@ void cNameValueParser::Parse(const char * a_Data, int a_Size) m_State = psValueRaw; break; } - i++; } // while (i < a_Size) break; } // case psEqual diff --git a/src/Item.cpp b/src/Item.cpp index 196a260ef..a44515019 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -246,7 +246,7 @@ void cItems::Delete(int a_Idx) -void cItems::Set(int a_Idx, ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemDamage) +void cItems::Set(int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage) { if ((a_Idx < 0) || (a_Idx >= (int)size())) { diff --git a/src/Item.h b/src/Item.h index c60d0542c..64a30ade1 100644 --- a/src/Item.h +++ b/src/Item.h @@ -181,9 +181,9 @@ public: void Delete(int a_Idx); void Clear (void) {clear(); } int Size (void) {return size(); } - void Set (int a_Idx, ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemDamage); + void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage); - void Add (ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemDamage) + void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage) { push_back(cItem(a_ItemType, a_ItemCount, a_ItemDamage)); } diff --git a/src/OSSupport/CriticalSection.h b/src/OSSupport/CriticalSection.h index 1bfe81439..73a71f5e1 100644 --- a/src/OSSupport/CriticalSection.h +++ b/src/OSSupport/CriticalSection.h @@ -14,9 +14,14 @@ public: void Lock(void); void Unlock(void); + // IsLocked/IsLockedByCurrentThread are only used in ASSERT statements, but because of the changes with ASSERT they must always be defined + // The fake versions (in Release) will not effect the program in any way #ifdef _DEBUG bool IsLocked(void); bool IsLockedByCurrentThread(void); + #else + bool IsLocked(void) { return false; } + bool IsLockedByCurrentThread(void) { return false; } #endif // _DEBUG private: diff --git a/src/OSSupport/Queue.h b/src/OSSupport/Queue.h index cde26e415..6c3d58295 100644 --- a/src/OSSupport/Queue.h +++ b/src/OSSupport/Queue.h @@ -19,123 +19,139 @@ implements the functions Delete() and Combine(). An example is given in cQueueFuncs and is used as the default behavior. */ -// this empty struct allows for the callback functions to be inlined +/// This empty struct allows for the callback functions to be inlined template<class T> struct cQueueFuncs { - public: - // Called when an Item is deleted form the queue without being returned - static void Delete(T) {}; - // Called when an Item is inserted with EnqueueItemIfNotPresent and - // there is another equal value already inserted - static void Combine(T& a_existing, const T& a_new) {}; +public: + + /// Called when an Item is deleted from the queue without being returned + static void Delete(T) {}; + + /// Called when an Item is inserted with EnqueueItemIfNotPresent and there is another equal value already inserted + static void Combine(T & a_existing, const T & a_new) {}; }; -template<class ItemType, class Funcs = cQueueFuncs<ItemType> > + + + + +template <class ItemType, class Funcs = cQueueFuncs<ItemType> > class cQueue { -// internal typedef for a List of Items -typedef typename std::list<ItemType> ListType; -// magic typedef to persuade clang that the iterator is a type -typedef typename ListType::iterator iterator; + // The actual storage type for the queue + typedef typename std::list<ItemType> QueueType; + + // Make iterator an alias for the QueueType's iterator + typedef typename QueueType::iterator iterator; + public: cQueue() {} ~cQueue() {} - // Enqueues an item to the queue, may block if other threads are accessing - // the queue. - void EnqueueItem(ItemType a_item) + + /// Enqueues an item to the queue, may block if other threads are accessing the queue. + void EnqueueItem(ItemType a_Item) { cCSLock Lock(m_CS); - m_contents.push_back(a_item); + m_Contents.push_back(a_Item); m_evtAdded.Set(); } - // Enqueues an item to the queue if not already present as determined with - // operator ==. Will block other threads from accessing the queue. - void EnqueueItemIfNotPresent(ItemType a_item) + + /// Enqueues an item in the queue if not already present (as determined by operator ==). Blocks other threads from accessing the queue. + void EnqueueItemIfNotPresent(ItemType a_Item) { cCSLock Lock(m_CS); - for (iterator itr = m_contents.begin(); itr != m_contents.end(); ++itr) + for (iterator itr = m_Contents.begin(); itr != m_Contents.end(); ++itr) { - if((*itr) == a_item) { - Funcs funcTable; - funcTable.Combine(*itr,a_item); + if ((*itr) == a_Item) + { + Funcs::Combine(*itr, a_Item); return; } } - m_contents.push_back(a_item); + m_Contents.push_back(a_Item); m_evtAdded.Set(); } - // Dequeues an Item from the queue if any are present. Returns true if - // successful. Value of item is undefined if Dequeuing was unsuccessful. - bool TryDequeueItem(ItemType& item) + + /// Dequeues an item from the queue if any are present. + /// Returns true if successful. Value of item is undefined if dequeuing was unsuccessful. + bool TryDequeueItem(ItemType & item) { cCSLock Lock(m_CS); - if (m_contents.size() == 0) + if (m_Contents.size() == 0) { return false; } - item = m_contents.front(); - m_contents.pop_front(); + item = m_Contents.front(); + m_Contents.pop_front(); m_evtRemoved.Set(); return true; } - // Dequeues an Item from the Queue, blocking until an Item is Available. - ItemType DequeueItem() + + /// Dequeues an item from the queue, blocking until an item is available. + ItemType DequeueItem(void) { cCSLock Lock(m_CS); - while (m_contents.size() == 0) + while (m_Contents.size() == 0) { - cCSUnlock Unlock(m_CS); + cCSUnlock Unlock(Lock); m_evtAdded.Wait(); } - ItemType item = m_contents.front(); - m_contents.pop_front(); + ItemType item = m_Contents.front(); + m_Contents.pop_front(); m_evtRemoved.Set(); return item; } - // Blocks Until the queue is Empty, Has a slight race condition which may - // cause it to miss the queue being empty. - void BlockTillEmpty() { - // There is a very slight race condition here if the load completes between the check - // and the wait. - while(!(Size() == 0)){m_evtRemoved.Wait();} + + /// Blocks until the queue is empty. + void BlockTillEmpty(void) + { + cCSLock Lock(m_CS); + while (!m_Contents.empty()) + { + cCSUnlock Unlock(Lock); + m_evtRemoved.Wait(); + } } - // Removes all Items from the Queue, calling Delete on each of them. - // can all be inlined when delete is a noop - void Clear() + + /// Removes all Items from the Queue, calling Delete on each of them. + void Clear(void) { cCSLock Lock(m_CS); - Funcs funcTable; - while (!m_contents.empty()) + while (!m_Contents.empty()) { - funcTable.Delete(m_contents.front()); - m_contents.pop_front(); + Funcs::Delete(m_Contents.front()); + m_Contents.pop_front(); } } - // Returns the Size at time of being called - // Do not use to detirmine weather to call DequeueItem, use TryDequeue instead - size_t Size() + + /// Returns the size at time of being called. + /// Do not use to determine whether to call DequeueItem(), use TryDequeueItem() instead + size_t Size(void) { cCSLock Lock(m_CS); - return m_contents.size(); + return m_Contents.size(); } - // Removes an Item from the queue - bool Remove(ItemType a_item) + + /// Removes the item from the queue. If there are multiple such items, only the first one is removed. + /// Returns true if the item has been removed, false if no such item found. + bool Remove(ItemType a_Item) { cCSLock Lock(m_CS); - for (iterator itr = m_contents.begin(); itr != m_contents.end(); ++itr) + for (iterator itr = m_Contents.begin(); itr != m_Contents.end(); ++itr) { - if((*itr) == a_item) { - m_contents.erase(itr); + if ((*itr) == a_Item) + { + m_Contents.erase(itr); m_evtRemoved.Set(); return true; } @@ -144,8 +160,19 @@ public: } private: - ListType m_contents; + /// The contents of the queue + QueueType m_Contents; + + /// Mutex that protects access to the queue contents cCriticalSection m_CS; + + /// Event that is signalled when an item is added cEvent m_evtAdded; + + /// Event that is signalled when an item is removed (both dequeued or erased) cEvent m_evtRemoved; }; + + + + diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 46ac4ef89..302d1298c 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -5,7 +5,6 @@ #include "Globals.h" #include "ChunkDataSerializer.h" -#include "cryptopp/randpool.h" #include "Protocol132.h" #include "../Root.h" #include "../Server.h" @@ -19,8 +18,20 @@ #include "../WorldStorage/FastNBT.h" #include "../StringCompression.h" +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) + #pragma warning(disable:4244) + #pragma warning(disable:4231) + #pragma warning(disable:4189) + #pragma warning(disable:4702) +#endif +#include "cryptopp/randpool.h" +#ifdef _MSC_VER + #pragma warning(pop) +#endif #define HANDLE_PACKET_READ(Proc, Type, Var) \ @@ -866,7 +877,7 @@ void cProtocol132::SendCompass(const cWorld & a_World) void cProtocol132::SendEncryptionKeyRequest(void) { cCSLock Lock(m_CSPacket); - WriteByte((char)0xfd); + WriteByte(0xfd); WriteString(cRoot::Get()->GetServer()->GetServerID()); WriteShort((short)m_ServerPublicKey.size()); SendData(m_ServerPublicKey.data(), m_ServerPublicKey.size()); @@ -914,7 +925,7 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A { // Send encryption key response: cCSLock Lock(m_CSPacket); - WriteByte((char)0xfc); + WriteByte(0xfc); WriteShort(0); WriteShort(0); Flush(); diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h index f76272b8d..d36384a88 100644 --- a/src/Protocol/Protocol132.h +++ b/src/Protocol/Protocol132.h @@ -10,9 +10,23 @@ #pragma once #include "Protocol125.h" + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) + #pragma warning(disable:4244) + #pragma warning(disable:4231) + #pragma warning(disable:4189) + #pragma warning(disable:4702) +#endif + #include "cryptopp/modes.h" #include "cryptopp/aes.h" +#ifdef _MSC_VER + #pragma warning(pop) +#endif + diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index 28122034c..926fe6ee8 100644 --- a/src/Protocol/Protocol14x.cpp +++ b/src/Protocol/Protocol14x.cpp @@ -16,7 +16,6 @@ Implements the 1.4.x protocol classes representing these protocols: #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" -#include "cryptopp/randpool.h" #include "../Item.h" #include "ChunkDataSerializer.h" #include "../Entities/Player.h" @@ -25,8 +24,20 @@ Implements the 1.4.x protocol classes representing these protocols: #include "../Entities/Pickup.h" #include "../Entities/FallingBlock.h" +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) + #pragma warning(disable:4244) + #pragma warning(disable:4231) + #pragma warning(disable:4189) + #pragma warning(disable:4702) +#endif +#include "cryptopp/randpool.h" +#ifdef _MSC_VER + #pragma warning(pop) +#endif #define HANDLE_PACKET_READ(Proc, Type, Var) \ diff --git a/src/Protocol/Protocol15x.cpp b/src/Protocol/Protocol15x.cpp index 7e2aa9490..0f1e59f10 100644 --- a/src/Protocol/Protocol15x.cpp +++ b/src/Protocol/Protocol15x.cpp @@ -112,7 +112,7 @@ int cProtocol150::ParseWindowClick(void) } // Convert Button, Mode, SlotNum and HeldItem into eClickAction: - eClickAction Action; + eClickAction Action = caUnknown; switch ((Mode << 8) | Button) { case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index bbbd5e973..8536689c3 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -986,7 +986,6 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) while (true) { UInt32 PacketLen; - int PacketStart = m_ReceivedData.GetDataStart(); if (!m_ReceivedData.ReadVarInt(PacketLen)) { // Not enough data diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index cc0eda1e7..23ff2365d 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -16,9 +16,23 @@ Declares the 1.7.x protocol classes: #include "Protocol.h" #include "../ByteBuffer.h" + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) + #pragma warning(disable:4244) + #pragma warning(disable:4231) + #pragma warning(disable:4189) + #pragma warning(disable:4702) +#endif + #include "cryptopp/modes.h" #include "cryptopp/aes.h" +#ifdef _MSC_VER + #pragma warning(pop) +#endif + diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 1cae4a750..e2ea0e6e5 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -198,7 +198,7 @@ void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) else { // This is used when the client sends a server-ping, respond with the default packet: - WriteByte ((char)0xff); // PACKET_DISCONNECT + WriteByte (0xff); // PACKET_DISCONNECT WriteString(a_Reason); } } diff --git a/src/Server.h b/src/Server.h index 1f94bb3da..e62c4c7b7 100644 --- a/src/Server.h +++ b/src/Server.h @@ -11,9 +11,24 @@ #include "OSSupport/SocketThreads.h" #include "OSSupport/ListenThread.h" + +#include "RCONServer.h" + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) + #pragma warning(disable:4244) + #pragma warning(disable:4231) + #pragma warning(disable:4189) + #pragma warning(disable:4702) +#endif + #include "cryptopp/rsa.h" #include "cryptopp/randpool.h" -#include "RCONServer.h" + +#ifdef _MSC_VER + #pragma warning(pop) +#endif diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 5c6b99d88..8d2352331 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -765,6 +765,54 @@ AString Base64Decode(const AString & a_Base64String) +AString Base64Encode(const AString & a_Input) +{ + static const char BASE64[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + + std::string output; + output.resize(((a_Input.size() + 2) / 3) * 4); + + size_t output_index = 0; + size_t size_full24 = (a_Input.size() / 3) * 3; + + for (size_t i = 0; i < size_full24; i += 3) + { + output[output_index++] = BASE64[(unsigned char)a_Input[i] >> 2]; + output[output_index++] = BASE64[((unsigned char)a_Input[i] << 4 | (unsigned char)a_Input[i + 1] >> 4) & 63]; + output[output_index++] = BASE64[((unsigned char)a_Input[i + 1] << 2 | (unsigned char)a_Input[i + 2] >> 6) & 63]; + output[output_index++] = BASE64[(unsigned char)a_Input[i + 2] & 63]; + } + + if (size_full24 < a_Input.size()) + { + output[output_index++] = BASE64[(unsigned char)a_Input[size_full24] >> 2]; + if (size_full24 + 1 == a_Input.size()) + { + output[output_index++] = BASE64[((unsigned char)a_Input[size_full24] << 4) & 63]; + output[output_index++] = '='; + } + else + { + output[output_index++] = BASE64[((unsigned char)a_Input[size_full24] << 4 | (unsigned char)a_Input[size_full24 + 1] >> 4) & 63]; + output[output_index++] = BASE64[((unsigned char)a_Input[size_full24 + 1] << 2) & 63]; + } + + output[output_index++] = '='; + } + assert(output_index == output.size()); + + return output; +} + + + + + short GetBEShort(const char * a_Mem) { return (((short)a_Mem[0]) << 8) | a_Mem[1]; diff --git a/src/StringUtils.h b/src/StringUtils.h index 471e843e4..2373f3843 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -81,6 +81,9 @@ extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, /// Decodes a Base64-encoded string into the raw data extern AString Base64Decode(const AString & a_Base64String); +/// Encodes a string into Base64 +extern AString Base64Encode(const AString & a_Input); + /// 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/World.h b/src/World.h index 67f1275c0..f90ddd90f 100644 --- a/src/World.h +++ b/src/World.h @@ -146,7 +146,7 @@ public: // Broadcast respective packets to all clients of the chunk where the event is taking place // (Please keep these alpha-sorted) void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); // tolua_export void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 5f4c112d5..6aec525a8 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -117,6 +117,10 @@ void cWorldStorage::WaitForLoadQueueEmpty(void) m_LoadQueue.BlockTillEmpty(); } + + + + void cWorldStorage::WaitForSaveQueueEmpty(void) { m_SaveQueue.BlockTillEmpty(); @@ -124,6 +128,8 @@ void cWorldStorage::WaitForSaveQueueEmpty(void) + + size_t cWorldStorage::GetLoadQueueLength(void) { return m_LoadQueue.Size(); @@ -144,8 +150,8 @@ size_t cWorldStorage::GetSaveQueueLength(void) void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) { - m_Event.Set(); m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); + m_Event.Set(); } @@ -154,8 +160,8 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, boo void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - m_Event.Set(); m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_Event.Set(); } @@ -166,6 +172,7 @@ void cWorldStorage::QueueSavedMessage(void) { // Pushes a special coord pair into the queue, signalizing a message instead m_SaveQueue.EnqueueItem(cChunkCoords(0, CHUNK_Y_MESSAGE, 0)); + m_Event.Set(); } |