diff options
57 files changed, 922 insertions, 303 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ae83662c9..53e836262 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ cmake_minimum_required (VERSION 2.8.7) # Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html ) enable_language(CXX C) +# Enable the support for solution folders in MSVC +if (MSVC) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + # These env variables are used for configuring Travis CI builds. # See https://github.com/mc-server/MCServer/pull/767 if(DEFINED ENV{TRAVIS_MCSERVER_BUILD_TYPE}) @@ -19,6 +24,7 @@ if(DEFINED ENV{TRAVIS_BUILD_WITH_COVERAGE}) endif() if(DEFINED ENV{MCSERVER_BUILD_ID}) + # The build info is defined by the build system (Travis / Jenkins) set(BUILD_ID $ENV{MCSERVER_BUILD_ID}) set(BUILD_SERIES_NAME $ENV{MCSERVER_BUILD_SERIES_NAME}) set(BUILD_DATETIME $ENV{MCSERVER_BUILD_DATETIME}) @@ -29,12 +35,41 @@ if(DEFINED ENV{MCSERVER_BUILD_ID}) execute_process( COMMAND git rev-parse HEAD RESULT_VARIABLE GIT_EXECUTED - OUTPUT_VARIABLE BUILD_COMMIT_ID) - string(STRIP ${BUILD_COMMIT_ID} BUILD_COMMIT_ID) + OUTPUT_VARIABLE BUILD_COMMIT_ID + ) + string(STRIP ${BUILD_COMMIT_ID} BUILD_COMMIT_ID) if (NOT (GIT_EXECUTED EQUAL 0)) message(FATAL_ERROR "Could not identifiy git commit id") endif() endif() +else() + # This is a local build, stuff in some basic info: + set(BUILD_ID "Unknown") + set(BUILD_SERIES_NAME "local build") + execute_process( + COMMAND git rev-parse HEAD + RESULT_VARIABLE GIT_EXECUTED + OUTPUT_VARIABLE BUILD_COMMIT_ID + ) + if (NOT(GIT_EXECUTED EQUAL 0)) + set(BUILD_COMMIT_ID "Unknown") + endif() + string(STRIP ${BUILD_COMMIT_ID} BUILD_COMMIT_ID) + execute_process( + COMMAND git log -1 --date=iso --pretty=format:%ai + RESULT_VARIABLE GIT_EXECUTED + OUTPUT_VARIABLE BUILD_DATETIME + ) + if (NOT(GIT_EXECUTED EQUAL 0)) + set(BUILD_DATETIME "Unknown") + endif() + string(STRIP ${BUILD_DATETIME} BUILD_DATETIME) + + # The BUILD_COMMIT_ID and BUILD_DATETIME aren't updated on each repo pull + # They are only updated when cmake re-configures the project + # Therefore mark them as "approx: " + set(BUILD_COMMIT_ID "approx: ${BUILD_COMMIT_ID}") + set(BUILD_DATETIME "approx: ${BUILD_DATETIME}") endif() # We need C++11 features, Visual Studio has those from VS2012, but it needs a new platform toolset for those; VS2013 supports them natively: @@ -67,6 +102,7 @@ if(${BUILD_UNSTABLE_TOOLS}) add_subdirectory(Tools/GeneratorPerformanceTest/) endif() +include(CheckCXXCompilerFlag) include(SetFlags.cmake) set_flags() set_lib_flags() @@ -102,6 +138,7 @@ set(SQLITECPP_RUN_DOXYGEN OFF CACHE BOOL "Run Doxygen C++ documentation tool set(SQLITECPP_BUILD_EXAMPLES OFF CACHE BOOL "Build examples." FORCE) set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." FORCE) set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "Add the internal SQLite3 source to the project." FORCE) +set(SQLITE_ENABLE_COLUMN_METADATA OFF CACHE BOOL "" FORCE) # Set options for LibEvent, disable all their tests and benchmarks: set(EVENT__DISABLE_OPENSSL YES CACHE BOOL "Disable OpenSSL in LibEvent" FORCE) @@ -130,7 +167,7 @@ add_subdirectory(lib/sqlite/) add_subdirectory(lib/SQLiteCpp/) add_subdirectory(lib/expat/) add_subdirectory(lib/luaexpat/) -add_subdirectory(lib/libevent/) +add_subdirectory(lib/libevent/ EXCLUDE_FROM_ALL) # Add proper include directories so that SQLiteCpp can find SQLite3: get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES) @@ -160,3 +197,13 @@ if(${SELF_TEST}) add_subdirectory (tests) endif() +# Put project into solution folders in MSVC: +if (MSVC) + set_target_properties(event_core event_extra expat jsoncpp lua luaexpat mbedtls sqlite SQLiteCpp tolualib zlib PROPERTIES FOLDER Lib) + set_target_properties(luaproxy tolua PROPERTIES FOLDER Support) + if (${SELF_TEST}) + set_target_properties(Network PROPERTIES FOLDER Lib) + set_target_properties(arraystocoords-exe coordinates-exe copies-exe copyblocks-exe creatable-exe EchoServer Google-exe ChunkBuffer NameLookup PROPERTIES FOLDER Tests) + endif() +endif() + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e57e6efb..1b43ed214 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ Here are the conventions: - This helps prevent mistakes such as `if (a & 1 == 0)` * * Use the provided wrappers for OS stuff: - - Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep` + - Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep` * No magic numbers, use named constants: - `E_ITEM_XXX`, `E_BLOCK_XXX` and `E_META_XXX` for items and blocks - `cEntity::etXXX` for entity types, `cMonster::mtXXX` for mob types diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3505d7155..82ae6a7a8 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3,11 +3,14 @@ Many people have contributed to MCServer, and this list attempts to broadcast at BasedDoge (Donated AlchemistVillage prefabs) bearbin (Alexander Harkness) beeduck +birkett (Anthony Birkett) derouinw Diusrex Duralex FakeTruth (founder) +HaoTNN Howaner +jan64 jasperarmstrong keyboard Lapayo diff --git a/Install/MCServer_high_detail_debug.cmd b/Install/MCServer_high_detail_debug.cmd index 384189c42..d94af8150 100644 --- a/Install/MCServer_high_detail_debug.cmd +++ b/Install/MCServer_high_detail_debug.cmd @@ -1 +1 @@ -MCServer /cdf
\ No newline at end of file +MCServer --crash-dump-full diff --git a/Install/MCServer_medium_detail_debug.cmd b/Install/MCServer_medium_detail_debug.cmd index b5bb0954c..0a33c27fd 100644 --- a/Install/MCServer_medium_detail_debug.cmd +++ b/Install/MCServer_medium_detail_debug.cmd @@ -1 +1 @@ -MCServer /cdg
\ No newline at end of file +MCServer --crash-dump-globals diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 4af01c0a4..87edb226a 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -100,6 +100,11 @@ g_APIDesc = CopyFrom = { Params = "BlockAreaSrc", Return = "", Notes = "Copies contents from BlockAreaSrc into self" }, CopyTo = { Params = "BlockAreaDst", Return = "", Notes = "Copies contents from self into BlockAreaDst." }, CountNonAirBlocks = { Params = "", Return = "number", Notes = "Returns the count of blocks that are not air. Returns 0 if blocktypes not available. Block metas are ignored (if present, air with any meta is still considered air)." }, + CountSpecificBlocks = + { + { Params = "BlockType", Return = "number", Notes = "Counts the number of occurences of the specified blocktype contained in the area." }, + { Params = "BlockType, BlockMeta", Return = "number", Notes = "Counts the number of occurrences of the specified blocktype + blockmeta combination contained in the area." }, + }, Create = { Params = "SizeX, SizeY, SizeZ, [DataTypes]", Return = "", Notes = "Initializes this BlockArea to an empty area of the specified size and origin of {0, 0, 0}. Any previous contents are lost." }, Crop = { Params = "AddMinX, SubMaxX, AddMinY, SubMaxY, AddMinZ, SubMaxZ", Return = "", Notes = "Crops the specified number of blocks from each border. Modifies the size of this blockarea object." }, DumpToRawFile = { Params = "FileName", Return = "", Notes = "Dumps the raw data into a file. For debugging purposes only." }, @@ -1917,6 +1922,8 @@ a_Player:OpenWindow(Window); SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." }, SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." }, SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." }, + SendAboveActionBarMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player (shows above action bar, doesn't show for < 1.8 clients)." }, + SendSystemMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player (doesn't show for < 1.8 clients)." }, SendRotation = { Params = "YawDegrees, PitchDegrees", Return = "", Notes = "Sends the specified rotation to the player, forcing them to look that way" }, SetBedPos = { Params = "{{Vector3i|Position}}", Return = "", Notes = "Sets the internal representation of the last bed position the player has slept in. The player will respawn at this position if they die." }, SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." }, @@ -2036,7 +2043,7 @@ a_Player:OpenWindow(Window); BroadcastChat = { { Params = "MessageText, MessageType", Return = "", Notes = "Broadcasts a message to all players, with its message type set to MessageType (default: mtCustom)." }, - { Params = "{{cCompositeChat|CompositeChat}}", Return = "", Notes = "Broadcasts a {{cCompositeChat|composite chat message} to all players." }, + { Params = "{{cCompositeChat|CompositeChat}}", Return = "", Notes = "Broadcasts a {{cCompositeChat|composite chat message}} to all players." }, }, BroadcastChatDeath = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtDeath. Use for when a player has died." }, BroadcastChatFailure = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtFailure. Use for a command that failed to run because of insufficient permissions, etc." }, @@ -2046,12 +2053,16 @@ a_Player:OpenWindow(Window); BroadcastChatLeave = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtLeave. Use for players leaving the server." }, BroadcastChatSuccess = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtSuccess. Use for success messages." }, BroadcastChatWarning = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtWarning. Use for concerning events, such as plugin reload etc." }, - CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br><br><b>NOTE</b>This function is currently unsafe, do not use!" }, + CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br><br><b>NOTE:</b> This function is currently unsafe, do not use!" }, FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "bool", Notes = "Calls the given callback function for the player with the name best matching the name string provided.<br>This function is case-insensitive and will match partial names.<br>Returns false if player not found or there is ambiguity, true otherwise. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre>" }, DoWithPlayerByUUID = { Params = "PlayerUUID, CallbackFunction", Return = "bool", Notes = "If there is the player with the uuid, calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." }, ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" }, ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" }, - Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." }, + Get = { Params = "", Return = "Root object", Notes = "(STATIC) This function returns the cRoot object." }, + GetBuildCommitID = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travis CI / Jenkins) it returns the exact commit hash used for the build. For unofficial local builds, returns the approximate commit hash (since the true one cannot be determined), formatted as \"approx: <CommitHash>\"." }, + GetBuildDateTime = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travic CI / Jenkins) it returns the date and time of the build. For unofficial local builds, returns the approximate datetime of the commit (since the true one cannot be determined), formatted as \"approx: <DateTime-iso8601>\"." }, + GetBuildID = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travis CI / Jenkins) it returns the unique ID of the build, as recognized by the build system. For unofficial local builds, returns the string \"Unknown\"." }, + GetBuildSeriesName = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travis CI / Jenkins) it returns the series name of the build (for example \"MCServer Windows x64 Master\"). For unofficial local builds, returns the string \"local build\"." }, GetCraftingRecipes = { Params = "", Return = "{{cCraftingRecipe|cCraftingRecipe}}", Notes = "Returns the CraftingRecipes object" }, GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." }, GetFurnaceFuelBurnTime = { Params = "{{cItem|Fuel}}", Return = "number", Notes = "(STATIC) Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel." }, diff --git a/MCServer/Plugins/APIDump/Hooks/OnKilling.lua b/MCServer/Plugins/APIDump/Hooks/OnKilling.lua index 8ec1cfe2e..5e84009db 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnKilling.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnKilling.lua @@ -17,6 +17,7 @@ return { { Name = "Victim", Type = "{{cPawn}}", Notes = "The player or mob that is about to be killed" }, { Name = "Killer", Type = "{{cEntity}}", Notes = "The entity that has caused the victim to lose the last point of health. May be nil for environment damage" }, + { Name = "TDI", Type = "{{TakeDamageInfo}}", Notes = "The damage type, cause and effects." }, }, Returns = [[ If the function returns false or no value, MCServer calls other plugins with this event. If the diff --git a/MCServer/Plugins/APIDump/main.css b/MCServer/Plugins/APIDump/main.css index 8041e0d01..e5685caab 100644 --- a/MCServer/Plugins/APIDump/main.css +++ b/MCServer/Plugins/APIDump/main.css @@ -61,7 +61,7 @@ footer font-family: Segoe UI Light, Helvetica; } -#content +#content, #timestamp { padding: 0px 25px 25px 25px; } diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index e841922b6..543a299af 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -153,6 +153,19 @@ end +--- Returns the timestamp in HTML format +-- The timestamp will be inserted to all generated HTML files +local function GetHtmlTimestamp() + return string.format("<div id='timestamp'>Generated on %s, Build ID %s, Commit %s</div>", + os.date("%Y-%m-%d %H:%M:%S"), + cRoot:GetBuildID(), cRoot:GetBuildCommitID() + ) +end + + + + + local function WriteArticles(f) f:write([[ <a name="articles"><h2>Articles</h2></a> @@ -296,7 +309,9 @@ local function WriteHtmlHook(a_Hook, a_HookNav) f:write("<p>", (example.Desc or "<i>missing Desc</i>"), "</p>\n"); f:write("<pre class=\"prettyprint lang-lua\">", (example.Code or "<i>missing Code</i>"), "\n</pre>\n\n"); end - f:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]); + f:write([[</td></tr></table></div><script>prettyPrint();</script>]]) + f:write(GetHtmlTimestamp()) + f:write([[</body></html>]]) f:close(); end @@ -941,8 +956,10 @@ local function WriteHtmlClass(a_ClassAPI, a_ClassMenu) end end - cf:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]); - cf:close(); + cf:write([[</td></tr></table></div><script>prettyPrint();</script>]]) + cf:write(GetHtmlTimestamp()) + cf:write([[</body></html>]]) + cf:close() end @@ -1320,11 +1337,10 @@ local function DumpAPIHtml(a_API) WriteStats(f); - f:write([[ </ul> - </div> - </body> -</html>]]); - f:close(); + f:write([[</ul></div>]]) + f:write(GetHtmlTimestamp()) + f:write([[</body></html>]]) + f:close() LOG("API subfolder written"); end diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index a49f8b5a6..bd0b94a06 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -1880,6 +1880,117 @@ end +--- Returns the square of the distance from the specified point to the specified line +local function SqDistPtFromLine(x, y, x1, y1, x2, y2) + local dx = x - x1 + local dy = y - y1 + local px = x2 - x1 + local py = y2 - y1 + local ss = px * dx + py * dy + local ds = px * px + py * py + + if (ss < 0) then + -- Return sqdistance from point 1 + return dx * dx + dy * dy + end + if (ss > ds) then + -- Return sqdistance from point 2 + return ((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)) + end + + -- Return sqdistance from the line + if ((px * px + py * py) == 0) then + return dx * dx + dy * dy + else + return (py * dx - px * dy) * (py * dx - px * dy) / (px * px + py * py) + end +end + + + + + +function HandleConsoleTestTracer(a_Split, a_EntireCmd) + -- Check required params: + if not(a_Split[7]) then + return true, "Usage: " .. a_Split[1] .. " <x1> <y1> <z1> <x2> <y2> <z2> [<WorldName>]" + end + local Coords = {} + for i = 1, 6 do + local v = tonumber(a_Split[i + 1]) + if not(v) then + return true, "Parameter " .. (i + 1) .. " (" .. tostring(a_Split[i + 1]) .. ") not a number " + end + Coords[i] = v + end + + -- Get the world in which to test: + local World + if (a_Split[8]) then + World = cRoot:GetWorld(a_Split[2]) + else + World = cRoot:Get():GetDefaultWorld() + end + if not(World) then + return true, "No such world" + end + + -- Define the callbacks to use for tracing: + local Callbacks = + { + OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace) + LOG(string.format("{%d, %d, %d}: %s", a_BlockX, a_BlockY, a_BlockZ, ItemToString(cItem(a_BlockType, 1, a_BlockMeta)))) + end, + OnNextBlockNoData = function(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace) + LOG(string.format("{%d, %d, %d} (no data)", a_BlockX, a_BlockY, a_BlockZ)) + end, + OnNoChunk = function() + LOG("Chunk not loaded") + end, + OnNoMoreHits = function() + LOG("Trace finished") + end, + OnOutOfWorld = function() + LOG("Out of world") + end, + OnIntoWorld = function() + LOG("Into world") + end, + } + + -- Approximate the chunks needed for the trace by iterating over all chunks and measuring their center's distance from the traced line + local Chunks = {} + local sx = math.floor(Coords[1] / 16) + local sz = math.floor(Coords[3] / 16) + local ex = math.floor(Coords[4] / 16) + local ez = math.floor(Coords[6] / 16) + local sgnx = (sx < ex) and 1 or -1 + local sgnz = (sz < ez) and 1 or -1 + for z = sz, ez, sgnz do + local ChunkCenterZ = z * 16 + 8 + for x = sx, ex, sgnx do + local ChunkCenterX = x * 16 + 8 + local sqdist = SqDistPtFromLine(ChunkCenterX, ChunkCenterZ, Coords[1], Coords[3], Coords[4], Coords[6]) + if (sqdist <= 128) then + table.insert(Chunks, {x, z}) + end + end + end + + -- Load the chunks and do the trace once loaded: + World:ChunkStay(Chunks, + nil, + function() + cLineBlockTracer:Trace(World, Callbacks, Coords[1], Coords[2], Coords[3], Coords[4], Coords[5], Coords[6]) + end + ) + return true +end + + + + + function HandleConsoleBBox(a_Split) local bbox = cBoundingBox(0, 10, 0, 10, 0, 10) local v1 = Vector3d(1, 1, 1) diff --git a/MCServer/Plugins/Debuggers/Info.lua b/MCServer/Plugins/Debuggers/Info.lua index 2e170487b..a76690ea1 100644 --- a/MCServer/Plugins/Debuggers/Info.lua +++ b/MCServer/Plugins/Debuggers/Info.lua @@ -235,6 +235,12 @@ g_PluginInfo = Handler = HandleConsoleSchedule, HelpString = "Tests the world scheduling", }, + + ["testtracer"] = + { + Handler = HandleConsoleTestTracer, + HelpString = "Tests the cLineBlockTracer", + } }, -- ConsoleCommands } -- g_PluginInfo diff --git a/MCServer/install_windows_service.cmd b/MCServer/install_windows_service.cmd index ba8a8c128..d6b6c15a3 100644 --- a/MCServer/install_windows_service.cmd +++ b/MCServer/install_windows_service.cmd @@ -3,5 +3,5 @@ rem Alter this if you need to install multiple instances. set SERVICENAME="MCServer"
set CURRENTDIR=%CD%
-sc create %SERVICENAME% binPath= "%CURRENTDIR%\MCServer.exe /service" start= auto DisplayName= %SERVICENAME%
+sc create %SERVICENAME% binPath= "%CURRENTDIR%\MCServer.exe -d" start= auto DisplayName= %SERVICENAME%
sc description %SERVICENAME% "Minecraft server instance"
\ No newline at end of file diff --git a/SetFlags.cmake b/SetFlags.cmake index b79551eef..57cab5a1c 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -63,7 +63,7 @@ macro(set_flags) set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") elseif(APPLE) - + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) @@ -262,8 +262,11 @@ macro(set_exe_flags) add_flags_cxx("-Wno-documentation") endif() if ("${CLANG_VERSION}" VERSION_GREATER 3.5) - # Use this flag to ignore error for a reserved macro problem in sqlite 3 - add_flags_cxx("-Wno-reserved-id-macro") + check_cxx_compiler_flag(-Wno-reserved-id-macro HAS_NO_RESERVED_ID_MACRO) + if (HAS_NO_RESERVED_ID_MACRO) + # Use this flag to ignore error for a reserved macro problem in sqlite 3 + add_flags_cxx("-Wno-reserved-id-macro") + endif() endif() endif() endif() @@ -277,7 +280,7 @@ endmacro() # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=missing-prototypes -Wno-error=deprecated") # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=shadow -Wno-error=old-style-cast -Wno-error=switch-enum -Wno-error=switch") # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=float-equal -Wno-error=global-constructors") - + # if ("${CLANG_VERSION}" VERSION_GREATER 3.0) # # flags that are not present in 3.0 # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=covered-switch-default ") @@ -286,4 +289,3 @@ endmacro() # endif() # endforeach() # endif() - diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index 0d38a87f1..80c6f5be2 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -22,7 +22,7 @@ static const Byte g_Zeroes[4096] = {0}; int main(int argc, char ** argv) { - cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * consoleLogListener = MakeConsoleListener(false); cLogger::cListener * fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/Tools/ProtoProxy/ProtoProxy.cpp b/Tools/ProtoProxy/ProtoProxy.cpp index 3f427f83f..2d27d7556 100644 --- a/Tools/ProtoProxy/ProtoProxy.cpp +++ b/Tools/ProtoProxy/ProtoProxy.cpp @@ -16,7 +16,7 @@ int main(int argc, char ** argv) { // Initialize logging subsystem: cLogger::InitiateMultithreading(); - auto consoleLogListener = MakeConsoleListener(); + auto consoleLogListener = MakeConsoleListener(false); auto fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/lib/SQLiteCpp b/lib/SQLiteCpp -Subproject b17195b8d03e8908807c51f4d6ce610b148fc1b +Subproject 49679e7b54726e2d94d3aad76a65aeb9c1088af diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index bce1891e2..7655d8c83 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -34,6 +34,7 @@ #include "../CompositeChat.h" #include "../StringCompression.h" #include "../CommandOutput.h" +#include "../BuildInfo.h" @@ -2079,6 +2080,50 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) +static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + L.Push(BUILD_COMMIT_ID); + return 1; +} + + + + + +static int tolua_cRoot_GetBuildDateTime(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + L.Push(BUILD_DATETIME); + return 1; +} + + + + + +static int tolua_cRoot_GetBuildID(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + L.Push(BUILD_ID); + return 1; +} + + + + + +static int tolua_cRoot_GetBuildSeriesName(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + L.Push(BUILD_SERIES_NAME); + return 1; +} + + + + + static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) { cLuaState L(tolua_S); @@ -2092,7 +2137,8 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) } // Check the input param: - cItem * Input = (cItem *)tolua_tousertype(L, 2, nullptr); + cItem * Input = nullptr; + L.GetStackValue(2, Input); if (Input == nullptr) { LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing."); @@ -2109,9 +2155,9 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) } // Push the output, number of ticks and input as the three return values: - tolua_pushusertype(L, Recipe->Out, "const cItem"); - tolua_pushnumber (L, (lua_Number)(Recipe->CookTime)); - tolua_pushusertype(L, Recipe->In, "const cItem"); + L.Push(Recipe->Out); + L.Push(Recipe->CookTime); + L.Push(Recipe->In); return 3; } @@ -2868,6 +2914,10 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>); tolua_function(tolua_S, "ForEachPlayer", ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); tolua_function(tolua_S, "ForEachWorld", ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); + tolua_function(tolua_S, "GetBuildCommitID", tolua_cRoot_GetBuildCommitID); + tolua_function(tolua_S, "GetBuildDateTime", tolua_cRoot_GetBuildDateTime); + tolua_function(tolua_S, "GetBuildID", tolua_cRoot_GetBuildID); + tolua_function(tolua_S, "GetBuildSeriesName", tolua_cRoot_GetBuildSeriesName); tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe); tolua_endmodule(tolua_S); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 7982afc31..938351207 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -1665,6 +1665,65 @@ size_t cBlockArea::CountNonAirBlocks(void) const +size_t cBlockArea::CountSpecificBlocks(BLOCKTYPE a_BlockType) const +{ + // If blocktypes are not valid, log a warning and return zero occurences: + if (m_BlockTypes == nullptr) + { + LOGWARNING("%s: BlockTypes not available!", __FUNCTION__); + return 0; + } + + // Count the blocks: + size_t num = GetBlockCount(); + size_t res = 0; + for (size_t i = 0; i < num; i++) + { + if (m_BlockTypes[i] == a_BlockType) + { + res++; + } + } + return res; +} + + + + + +size_t cBlockArea::CountSpecificBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const +{ + // If blocktypes are not valid, log a warning and return zero occurences: + if (m_BlockTypes == nullptr) + { + LOGWARNING("%s: BlockTypes not available!", __FUNCTION__); + return 0; + } + + // If blockmetas are not valid, log a warning and count only blocktypes: + if (m_BlockMetas == nullptr) + { + LOGWARNING("%s: BlockMetas not available, comparing blocktypes only!", __FUNCTION__); + return CountSpecificBlocks(a_BlockType); + } + + // Count the blocks: + size_t num = GetBlockCount(); + size_t res = 0; + for (size_t i = 0; i < num; i++) + { + if ((m_BlockTypes[i] == a_BlockType) && (m_BlockMetas[i] == a_BlockMeta)) + { + res++; + } + } + return res; +} + + + + + void cBlockArea::GetNonAirCropRelCoords(int & a_MinRelX, int & a_MinRelY, int & a_MinRelZ, int & a_MaxRelX, int & a_MaxRelY, int & a_MaxRelZ, BLOCKTYPE a_IgnoreBlockType) { // Check if blocktypes are valid: diff --git a/src/BlockArea.h b/src/BlockArea.h index 4b672029b..a9963b4ef 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -308,6 +308,15 @@ public: Returns 0 if blocktypes not available. Block metas are ignored (if present, air with any meta is still considered air). */ size_t CountNonAirBlocks(void) const; + /** Returns how many times the specified block is contained in the area. + The blocks' meta values are ignored, only the blocktype is compared. */ + size_t CountSpecificBlocks(BLOCKTYPE a_BlockType) const; + + /** Returns how many times the specified block is contained in the area. + Both the block's type and meta must match in order to be counted in. + If the block metas aren't present in the area, logs a warning and ignores the meta specification. */ + size_t CountSpecificBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const; + // tolua_end /** Returns the minimum and maximum coords in each direction for the first non-ignored block in each direction. diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index 2621b560b..d1588160d 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -32,7 +32,8 @@ cFurnaceEntity::cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY m_NeedCookTime(0), m_TimeCooked(0), m_FuelBurnTime(0), - m_TimeBurned(0) + m_TimeBurned(0), + m_IsLoading(false) { m_Contents.AddListener(*this); } @@ -178,20 +179,15 @@ void cFurnaceEntity::BurnNewFuel(void) { cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); int NewTime = FR->GetBurnTime(m_Contents.GetSlot(fsFuel)); - if (NewTime == 0) + if ((NewTime == 0) || !CanCookInputToOutput()) { // The item in the fuel slot is not suitable + // or the input and output isn't available for cooking SetBurnTimes(0, 0); SetIsCooking(false); return; } - // Is the input and output ready for cooking? - if (!CanCookInputToOutput()) - { - return; - } - // Burn one new fuel: SetBurnTimes(NewTime, 0); SetIsCooking(true); @@ -218,6 +214,11 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) return; } + if (m_IsLoading) + { + return; + } + ASSERT(a_ItemGrid == &m_Contents); switch (a_SlotNum) { @@ -238,7 +239,10 @@ void cFurnaceEntity::UpdateInput(void) if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput)) { // The input is different from what we had before, reset the cooking time - m_TimeCooked = 0; + if (!m_IsLoading) + { + m_TimeCooked = 0; + } } m_LastInput = m_Contents.GetSlot(fsInput); @@ -253,13 +257,17 @@ void cFurnaceEntity::UpdateInput(void) else { m_NeedCookTime = m_CurrentRecipe->CookTime; - SetIsCooking(true); // Start burning new fuel if there's no flame now: if (GetFuelBurnTimeLeft() <= 0) { BurnNewFuel(); } + // Already burning, set cooking to ensure that cooking is occuring + else + { + SetIsCooking(true); + } } } @@ -293,11 +301,19 @@ void cFurnaceEntity::UpdateOutput(void) return; } - // No need to burn new fuel, the Tick() function will take care of that - // Can cook, start cooking if not already underway: m_NeedCookTime = m_CurrentRecipe->CookTime; - SetIsCooking(m_FuelBurnTime > 0); + + // Check if fuel needs to start a burn + if (GetFuelBurnTimeLeft() <= 0) + { + BurnNewFuel(); + } + // Already burning, set cooking to ensure that cooking is occuring + else + { + SetIsCooking(true); + } } diff --git a/src/BlockEntities/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h index 8b3ba3e36..8734d763c 100644 --- a/src/BlockEntities/FurnaceEntity.h +++ b/src/BlockEntities/FurnaceEntity.h @@ -101,6 +101,11 @@ public: m_TimeCooked = a_TimeCooked; } + void SetLoading(bool a_IsLoading) + { + m_IsLoading = a_IsLoading; + } + protected: /** Block meta of the block currently represented by this entity */ @@ -129,6 +134,9 @@ protected: /** Amount of ticks that the current fuel has been burning */ int m_TimeBurned; + + /** Is the block currently being loaded into the world? */ + bool m_IsLoading; /** Sends the specified progressbar value to all clients of the window */ void BroadcastProgress(short a_ProgressbarID, short a_Value); diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index d65d9722d..154cd610e 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -73,8 +73,13 @@ public: return 0x0; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } + inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x7) @@ -93,6 +98,7 @@ public: } } + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { NIBBLETYPE Meta; diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 50552c788..4d16d2552 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -89,6 +89,10 @@ public: return 0; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } } ; diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index f49f1adc7..d727f8f8e 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -64,6 +64,10 @@ public: return 0x2; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 5792d280b..8d676b56f 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -67,6 +67,10 @@ public: case BLOCK_FACE_YM: return 0x0; case BLOCK_FACE_NONE: return 0x6; } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } diff --git a/src/Blocks/BlockQuartz.h b/src/Blocks/BlockQuartz.h index 6f5c23902..b936a7e4a 100644 --- a/src/Blocks/BlockQuartz.h +++ b/src/Blocks/BlockQuartz.h @@ -36,6 +36,7 @@ public: return true; } + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_QuartzMeta) { switch (a_BlockFace) @@ -64,5 +65,9 @@ public: return a_QuartzMeta; // No idea, give a special meta (all sides the same) } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } } ; diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h index 74b05e33c..e52fbaa2f 100644 --- a/src/Blocks/BlockSideways.h +++ b/src/Blocks/BlockSideways.h @@ -64,6 +64,10 @@ public: return a_Meta | 0xC; // No idea, give a special meta } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } } ; diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 2841e3e08..a1d2dff6f 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -66,6 +66,7 @@ public: return true; } + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) { switch (a_BlockFace) @@ -82,8 +83,13 @@ public: return 0; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } + inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) @@ -100,6 +106,7 @@ public: } } + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { NIBBLETYPE Meta; diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index c7a96d393..39892af5a 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -16,6 +16,7 @@ public: { } + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -29,6 +30,7 @@ public: return true; } + inline static NIBBLETYPE DirectionToMetadata(eBlockFace a_Direction) { switch (a_Direction) @@ -45,8 +47,13 @@ public: return 0x0; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + #endif } + inline static eBlockFace MetadataToDirection(NIBBLETYPE a_Meta) { switch (a_Meta & 0x03) @@ -59,6 +66,7 @@ public: } } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to zero diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5556ddc4d..c68795bb3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,6 +83,7 @@ SET (HDRS BlockTracer.h Broadcaster.h BoundingBox.h + BuildInfo.h BuildInfo.h.cmake ByteBuffer.h ChatColor.h diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index e3f63b091..d89f7ab77 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2113,6 +2113,64 @@ void cClientHandle::SendChat(const cCompositeChat & a_Message) +void cClientHandle::SendChatAboveActionBar(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) +{ + cWorld * World = GetPlayer()->GetWorld(); + if (World == nullptr) + { + World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); + if (World == nullptr) + { + World = cRoot::Get()->GetDefaultWorld(); + } + } + + AString Message = FormatMessageType(World->ShouldUseChatPrefixes(), a_ChatPrefix, a_AdditionalData); + m_Protocol->SendChatAboveActionBar(Message.append(a_Message)); +} + + + + + +void cClientHandle::SendChatAboveActionBar(const cCompositeChat & a_Message) +{ + m_Protocol->SendChatAboveActionBar(a_Message); +} + + + + + +void cClientHandle::SendChatSystem(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) +{ + cWorld * World = GetPlayer()->GetWorld(); + if (World == nullptr) + { + World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); + if (World == nullptr) + { + World = cRoot::Get()->GetDefaultWorld(); + } + } + + AString Message = FormatMessageType(World->ShouldUseChatPrefixes(), a_ChatPrefix, a_AdditionalData); + m_Protocol->SendChatSystem(Message.append(a_Message)); +} + + + + + +void cClientHandle::SendChatSystem(const cCompositeChat & a_Message) +{ + m_Protocol->SendChatSystem(a_Message); +} + + + + + void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { ASSERT(m_Player != nullptr); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index bcfa55825..13b5f87e4 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -150,6 +150,10 @@ public: // tolua_export void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes); void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = ""); void SendChat (const cCompositeChat & a_Message); + void SendChatAboveActionBar (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = ""); + void SendChatAboveActionBar (const cCompositeChat & a_Message); + void SendChatSystem (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = ""); + void SendChatSystem (const cCompositeChat & a_Message); void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer); void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player); void SendDestroyEntity (const cEntity & a_Entity); diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index a95ac5f84..c6a407d4b 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -168,7 +168,14 @@ void cCraftingGrid::ConsumeGrid(const cCraftingGrid & a_Grid) m_Items[ThisIdx].m_ItemCount -= NumWantedItems; if (m_Items[ThisIdx].m_ItemCount == 0) { - m_Items[ThisIdx].Clear(); + if ((m_Items[ThisIdx].m_ItemType == E_ITEM_MILK) || (m_Items[ThisIdx].m_ItemType == E_ITEM_WATER_BUCKET) || (m_Items[ThisIdx].m_ItemType == E_ITEM_LAVA_BUCKET)) + { + m_Items[ThisIdx] = cItem(E_ITEM_BUCKET, m_Items[ThisIdx].m_ItemCount); + } + else + { + m_Items[ThisIdx].Clear(); + } } } // for x, for y } diff --git a/src/Defines.h b/src/Defines.h index bbc69f79c..b167f69e3 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -133,6 +133,17 @@ enum eGameMode +enum eChatType +{ + ctChatBox = 0, + ctSystem = 1, + ctAboveActionBar = 2, +} ; + + + + + enum eWeather { eWeather_Sunny = 0, @@ -245,6 +256,10 @@ inline eBlockFace MirrorBlockFaceY(eBlockFace a_BlockFace) return a_BlockFace; }; } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return a_BlockFace; + #endif } @@ -267,6 +282,10 @@ inline eBlockFace RotateBlockFaceCCW(eBlockFace a_BlockFace) return a_BlockFace; } } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return a_BlockFace; + #endif } @@ -288,8 +307,16 @@ inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace) return a_BlockFace; }; } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return a_BlockFace; + #endif } + + + + inline eBlockFace ReverseBlockFace(eBlockFace a_BlockFace) { switch (a_BlockFace) @@ -302,9 +329,16 @@ inline eBlockFace ReverseBlockFace(eBlockFace a_BlockFace) case BLOCK_FACE_ZM: return BLOCK_FACE_ZP; case BLOCK_FACE_NONE: return a_BlockFace; } + #if !defined(__clang__) + ASSERT(!"Unknown BLOCK_FACE"); + return a_BlockFace; + #endif } + + + /** Returns the textual representation of the BlockFace constant. */ inline AString BlockFaceToString(eBlockFace a_BlockFace) { @@ -320,7 +354,7 @@ inline AString BlockFaceToString(eBlockFace a_BlockFace) } // clang optimisises this line away then warns that it has done so. #if !defined(__clang__) - return Printf("Unknown BLOCK_FACE: %d", a_BlockFace); + return Printf("Unknown BLOCK_FACE: %d", a_BlockFace); #endif } diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h index 4d70cd1a0..5d0aa17b3 100644 --- a/src/Entities/HangingEntity.h +++ b/src/Entities/HangingEntity.h @@ -46,6 +46,9 @@ public: protected: + Byte m_Facing; + + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override { @@ -53,6 +56,7 @@ protected: UNUSED(a_Chunk); } + /** Converts protocol hanging item facing to eBlockFace values */ inline static eBlockFace ProtocolFaceToBlockFace(Byte a_ProtocolFace) { @@ -77,6 +81,7 @@ protected: return Dir; } + /** Converts eBlockFace values to protocol hanging item faces */ inline static Byte BlockFaceToProtocolFace(eBlockFace a_BlockFace) { @@ -99,13 +104,17 @@ protected: Dir = cHangingEntity::BlockFaceToProtocolFace(BLOCK_FACE_XP); } + #if !defined(__clang__) + default: + { + ASSERT(!"Unknown BLOCK_FACE"); + return 0; + } + #endif } return Dir; } - - Byte m_Facing; - }; // tolua_export diff --git a/src/Entities/Player.h b/src/Entities/Player.h index a84fdd0c7..799990bf2 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -235,14 +235,19 @@ public: // tolua_begin - void SendMessage (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtCustom); } - void SendMessageInfo (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtInformation); } - void SendMessageFailure (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); } - void SendMessageSuccess (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtSuccess); } - void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); } - void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); } - void SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); } - void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); } + void SendMessage (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtCustom); } + void SendMessageInfo (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtInformation); } + void SendMessageFailure (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); } + void SendMessageSuccess (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtSuccess); } + void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); } + void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); } + void SendMessagePrivateMsg (const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); } + void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); } + + void SendSystemMessage (const AString & a_Message) { m_ClientHandle->SendChatSystem(a_Message, mtCustom); } + void SendAboveActionBarMessage(const AString & a_Message) { m_ClientHandle->SendChatAboveActionBar(a_Message, mtCustom); } + void SendSystemMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChatSystem(a_Message); } + void SendAboveActionBarMessage(const cCompositeChat & a_Message) { m_ClientHandle->SendChatAboveActionBar(a_Message); } const AString & GetName(void) const { return m_PlayerName; } void SetName(const AString & a_Name) { m_PlayerName = a_Name; } diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 88dade240..4ba896ef6 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -787,6 +787,13 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) Meta = E_META_CHEST_FACING_XP; break; } + #if !defined(__clang__) + default: + { + ASSERT(!"Unknown direction"); + return; + } + #endif } // switch (Dir) if ( diff --git a/src/Globals.h b/src/Globals.h index 8ff7b6894..b787a94da 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -220,6 +220,7 @@ template class SizeChecker<UInt8, 1>; #include <semaphore.h> #include <errno.h> #include <fcntl.h> + #include <unistd.h> #endif #if defined(ANDROID_NDK) @@ -264,7 +265,6 @@ template class SizeChecker<UInt8, 1>; // Common headers (part 1, without macros): #include "StringUtils.h" #include "OSSupport/CriticalSection.h" - #include "OSSupport/Semaphore.h" #include "OSSupport/Event.h" #include "OSSupport/File.h" #include "Logger.h" diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp index 315e8d082..587fa0e7c 100644 --- a/src/LineBlockTracer.cpp +++ b/src/LineBlockTracer.cpp @@ -154,38 +154,45 @@ bool cLineBlockTracer::MoveToNextBlock(void) { // Find out which of the current block's walls gets hit by the path: static const double EPS = 0.00001; - double Coeff = 1; - enum eDirection + enum { dirNONE, dirX, dirY, dirZ, } Direction = dirNONE; + + // Calculate the next YZ wall hit: + double Coeff = 1; if (std::abs(m_DiffX) > EPS) { double DestX = (m_DirX > 0) ? (m_CurrentX + 1) : m_CurrentX; - Coeff = (DestX - m_StartX) / m_DiffX; - if (Coeff <= 1) + double CoeffX = (DestX - m_StartX) / m_DiffX; + if (CoeffX <= 1) // We need to include equality for the last block in the trace { + Coeff = CoeffX; Direction = dirX; } } + + // If the next XZ wall hit is closer, use it instead: if (std::abs(m_DiffY) > EPS) { double DestY = (m_DirY > 0) ? (m_CurrentY + 1) : m_CurrentY; double CoeffY = (DestY - m_StartY) / m_DiffY; - if (CoeffY < Coeff) + if (CoeffY <= Coeff) // We need to include equality for the last block in the trace { Coeff = CoeffY; Direction = dirY; } } + + // If the next XY wall hit is closer, use it instead: if (std::abs(m_DiffZ) > EPS) { double DestZ = (m_DirZ > 0) ? (m_CurrentZ + 1) : m_CurrentZ; double CoeffZ = (DestZ - m_StartZ) / m_DiffZ; - if (CoeffZ < Coeff) + if (CoeffZ <= Coeff) // We need to include equality for the last block in the trace { Direction = dirZ; } diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 31b12af1e..132751e8e 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -238,8 +238,26 @@ public: -cLogger::cListener * MakeConsoleListener(void) +// Listener for when stdout is closed, i.e. When running as a daemon. +class cNullConsoleListener + : public cLogger::cListener +{ + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + } +}; + + + + + +cLogger::cListener * MakeConsoleListener(bool a_IsService) { + if (a_IsService) + { + return new cNullConsoleListener; + } + #ifdef _WIN32 // See whether we are writing to a console the default console attrib: bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h index c419aa75a..a7f9a35a5 100644 --- a/src/LoggerListeners.h +++ b/src/LoggerListeners.h @@ -25,7 +25,7 @@ private: -cLogger::cListener * MakeConsoleListener(); +cLogger::cListener * MakeConsoleListener(bool a_IsService); diff --git a/src/MobCensus.cpp b/src/MobCensus.cpp index ca960a2bc..79b5176d2 100644 --- a/src/MobCensus.cpp +++ b/src/MobCensus.cpp @@ -48,6 +48,10 @@ int cMobCensus::GetCapMultiplier(cMonster::eFamily a_MobFamily) return -1; } } + #if !defined(__clang__) + ASSERT(!"Unknown mob family"); + return -1; + #endif } diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index d1db0373d..df47394ae 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -15,7 +15,6 @@ SET (SRCS IsThread.cpp NetworkInterfaceEnum.cpp NetworkSingleton.cpp - Semaphore.cpp ServerHandleImpl.cpp StackTrace.cpp TCPLinkImpl.cpp @@ -34,7 +33,6 @@ SET (HDRS Network.h NetworkSingleton.h Queue.h - Semaphore.h ServerHandleImpl.h StackTrace.h TCPLinkImpl.h diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp index 760e536a1..38144ead3 100644 --- a/src/OSSupport/Event.cpp +++ b/src/OSSupport/Event.cpp @@ -1,8 +1,8 @@ // Event.cpp -// Implements the cEvent object representing an OS-specific synchronization primitive that can be waited-for -// Implemented as an Event on Win and as a 1-semaphore on *nix +// Interfaces to the cEvent object representing a synchronization primitive that can be waited-for +// Implemented using C++11 condition variable and mutex #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules diff --git a/src/OSSupport/Semaphore.cpp b/src/OSSupport/Semaphore.cpp deleted file mode 100644 index 6a2d57901..000000000 --- a/src/OSSupport/Semaphore.cpp +++ /dev/null @@ -1,107 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - - - - - -cSemaphore::cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount /* = 0 */) -#ifndef _WIN32 - : m_bNamed( false) -#endif -{ -#ifndef _WIN32 - (void)a_MaxCount; - m_Handle = new sem_t; - if (sem_init( (sem_t*)m_Handle, 0, 0)) - { - LOG("WARNING cSemaphore: Could not create unnamed semaphore, fallback to named."); - delete (sem_t*)m_Handle; // named semaphores return their own address - m_bNamed = true; - - AString Name; - Printf(Name, "cSemaphore%p", this); - m_Handle = sem_open(Name.c_str(), O_CREAT, 777, a_InitialCount); - if (m_Handle == SEM_FAILED) - { - LOG("ERROR: Could not create Semaphore. (%i)", errno); - } - else - { - if (sem_unlink(Name.c_str()) != 0) - { - LOG("ERROR: Could not unlink cSemaphore. (%i)", errno); - } - } - } -#else - m_Handle = CreateSemaphore( - nullptr, // security attribute - a_InitialCount, // initial count - a_MaxCount, // maximum count - 0 // name (optional) - ); -#endif -} - - - - - -cSemaphore::~cSemaphore() -{ -#ifdef _WIN32 - CloseHandle( m_Handle); -#else - if (m_bNamed) - { - if (sem_close( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not close cSemaphore. (%i)", errno); - } - } - else - { - sem_destroy( (sem_t*)m_Handle); - delete (sem_t*)m_Handle; - } - m_Handle = 0; - -#endif -} - - - - - -void cSemaphore::Wait() -{ -#ifndef _WIN32 - if (sem_wait( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not wait for cSemaphore. (%i)", errno); - } -#else - WaitForSingleObject( m_Handle, INFINITE); -#endif -} - - - - - -void cSemaphore::Signal() -{ -#ifndef _WIN32 - if (sem_post( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not signal cSemaphore. (%i)", errno); - } -#else - ReleaseSemaphore( m_Handle, 1, nullptr); -#endif -} - - - - diff --git a/src/OSSupport/Semaphore.h b/src/OSSupport/Semaphore.h deleted file mode 100644 index 57fa4bdb2..000000000 --- a/src/OSSupport/Semaphore.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -class cSemaphore -{ -public: - cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount = 0); - ~cSemaphore(); - - void Wait(); - void Signal(); -private: - void * m_Handle; // HANDLE pointer - -#ifndef _WIN32 - bool m_bNamed; -#endif -}; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 7be72014a..1a19249bf 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -70,6 +70,12 @@ public: virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0; virtual void SendChat (const AString & a_Message) = 0; virtual void SendChat (const cCompositeChat & a_Message) = 0; + virtual void SendChatAboveActionBar (const AString & a_Message) = 0; + virtual void SendChatAboveActionBar (const cCompositeChat & a_Message) = 0; + virtual void SendChatSystem (const AString & a_Message) = 0; + virtual void SendChatSystem (const cCompositeChat & a_Message) = 0; + virtual void SendChatType (const AString & a_Message, eChatType type) = 0; + virtual void SendChatType (const cCompositeChat & a_Message, eChatType type) = 0; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) = 0; virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 6aa36e2a5..3d96071b5 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -247,8 +247,67 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV void cProtocol172::SendChat(const AString & a_Message) { + this->SendChatType(a_Message, ctChatBox); +} + + + + + +void cProtocol172::SendChat(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctChatBox); +} + + + + + +void cProtocol172::SendChatSystem(const AString & a_Message) +{ + this->SendChatType(a_Message, ctSystem); +} + + + + + +void cProtocol172::SendChatSystem(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctSystem); +} + + + + + +void cProtocol172::SendChatAboveActionBar(const AString & a_Message) +{ + this->SendChatType(a_Message, ctAboveActionBar); +} + + + + + +void cProtocol172::SendChatAboveActionBar(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctAboveActionBar); +} + + + + + +void cProtocol172::SendChatType(const AString & a_Message, eChatType type) +{ ASSERT(m_State == 3); // In game mode? - + + if (type != ctChatBox) // 1.7.2 doesn't support anything else + { + return; + } + cPacketizer Pkt(*this, 0x02); // Chat Message packet Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); } @@ -257,10 +316,15 @@ void cProtocol172::SendChat(const AString & a_Message) -void cProtocol172::SendChat(const cCompositeChat & a_Message) +void cProtocol172::SendChatType(const cCompositeChat & a_Message, eChatType type) { ASSERT(m_State == 3); // In game mode? + if (type != ctChatBox) // 1.7.2 doesn't support anything else + { + return; + } + cWorld * World = m_Client->GetPlayer()->GetWorld(); bool ShouldUseChatPrefixes = (World == nullptr) ? false : World->ShouldUseChatPrefixes(); @@ -1041,8 +1105,8 @@ void cProtocol172::SendExperience (void) cPacketizer Pkt(*this, 0x1f); // Experience Packet cPlayer * Player = m_Client->GetPlayer(); Pkt.WriteBEFloat(Player->GetXpPercentage()); - Pkt.WriteBEInt16(static_cast<Int16>(std::max<int>(Player->GetXpLevel(), std::numeric_limits<Int16>::max()))); - Pkt.WriteBEInt16(static_cast<Int16>(std::max<int>(Player->GetCurrentXp(), std::numeric_limits<Int16>::max()))); + Pkt.WriteBEInt16(static_cast<Int16>(std::min<int>(Player->GetXpLevel(), std::numeric_limits<Int16>::max()))); + Pkt.WriteBEInt16(static_cast<Int16>(std::min<int>(Player->GetCurrentXp(), std::numeric_limits<Int16>::max()))); } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index ead2935b0..b07fa9ed9 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -68,6 +68,12 @@ public: virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; + virtual void SendChatAboveActionBar (const AString & a_Message) override; + virtual void SendChatAboveActionBar (const cCompositeChat & a_Message) override; + virtual void SendChatSystem (const AString & a_Message) override; + virtual void SendChatSystem (const cCompositeChat & a_Message) override; + virtual void SendChatType (const AString & a_Message, eChatType type) override; + virtual void SendChatType (const cCompositeChat & a_Message, eChatType type) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index d06022ce0..d9449283b 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -234,18 +234,72 @@ void cProtocol180::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV void cProtocol180::SendChat(const AString & a_Message) { + this->SendChatType(a_Message, ctChatBox); +} + + + + + +void cProtocol180::SendChat(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctChatBox); +} + + + + + +void cProtocol180::SendChatSystem(const AString & a_Message) +{ + this->SendChatType(a_Message, ctSystem); +} + + + + + +void cProtocol180::SendChatSystem(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctSystem); +} + + + + + +void cProtocol180::SendChatAboveActionBar(const AString & a_Message) +{ + this->SendChatType(a_Message, ctAboveActionBar); +} + + + + + +void cProtocol180::SendChatAboveActionBar(const cCompositeChat & a_Message) +{ + this->SendChatType(a_Message, ctAboveActionBar); +} + + + + + +void cProtocol180::SendChatType(const AString & a_Message, eChatType type) +{ ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x02); // Chat Message packet Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); - Pkt.WriteBEInt8(0); + Pkt.WriteBEInt8(type); } -void cProtocol180::SendChat(const cCompositeChat & a_Message) +void cProtocol180::SendChatType(const cCompositeChat & a_Message, eChatType type) { ASSERT(m_State == 3); // In game mode? @@ -255,7 +309,7 @@ void cProtocol180::SendChat(const cCompositeChat & a_Message) // Send the message to the client: cPacketizer Pkt(*this, 0x02); Pkt.WriteString(a_Message.CreateJsonString(ShouldUseChatPrefixes)); - Pkt.WriteBEInt8(0); + Pkt.WriteBEInt8(type); } diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h index 6143e8b4e..36ed251fe 100644 --- a/src/Protocol/Protocol18x.h +++ b/src/Protocol/Protocol18x.h @@ -67,6 +67,12 @@ public: virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; + virtual void SendChatAboveActionBar (const AString & a_Message) override; + virtual void SendChatAboveActionBar (const cCompositeChat & a_Message) override; + virtual void SendChatSystem (const AString & a_Message) override; + virtual void SendChatSystem (const cCompositeChat & a_Message) override; + virtual void SendChatType (const AString & a_Message, eChatType type) override; + virtual void SendChatType (const cCompositeChat & a_Message, eChatType type) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 477f2d71e..c89c745a4 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -158,6 +158,66 @@ void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message) +void cProtocolRecognizer::SendChatAboveActionBar(const AString & a_Message) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatAboveActionBar(a_Message); +} + + + + + +void cProtocolRecognizer::SendChatAboveActionBar(const cCompositeChat & a_Message) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatAboveActionBar(a_Message); +} + + + + + +void cProtocolRecognizer::SendChatSystem(const AString & a_Message) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatSystem(a_Message); +} + + + + + +void cProtocolRecognizer::SendChatSystem(const cCompositeChat & a_Message) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatSystem(a_Message); +} + + + + + +void cProtocolRecognizer::SendChatType(const AString & a_Message, eChatType type) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatType(a_Message, type); +} + + + + + +void cProtocolRecognizer::SendChatType(const cCompositeChat & a_Message, eChatType type) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendChatType(a_Message, type); +} + + + + + void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { ASSERT(m_Protocol != nullptr); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 956b5dcc0..29eddcbc9 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -55,6 +55,12 @@ public: virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; virtual void SendChat (const AString & a_Message) override; virtual void SendChat (const cCompositeChat & a_Message) override; + virtual void SendChatAboveActionBar (const AString & a_Message) override; + virtual void SendChatAboveActionBar (const cCompositeChat & a_Message) override; + virtual void SendChatSystem (const AString & a_Message) override; + virtual void SendChatSystem (const cCompositeChat & a_Message) override; + virtual void SendChatType (const AString & a_Message, eChatType type) override; + virtual void SendChatType (const cCompositeChat & a_Message, eChatType type) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; diff --git a/src/Root.cpp b/src/Root.cpp index 54e65b6da..8d344ee65 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -106,7 +106,7 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo) EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling #endif - cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * consoleLogListener = MakeConsoleListener(m_RunAsService); cLogger::cListener * fileLogListener = new cFileListener(); cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(fileLogListener); diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index f77197914..860eb3a4a 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -257,6 +257,9 @@ bool cParsedNBT::ReadTag(void) return true; } + #if !defined(__clang__) + default: + #endif case TAG_Min: { ASSERT(!"Unhandled NBT tag type"); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 392b9bf83..8ca49c2c0 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -1052,7 +1052,8 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag } std::unique_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); - + Furnace->SetLoading(true); + // Load slots: for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child)) { @@ -1085,9 +1086,9 @@ cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_Tag // Anvil doesn't store the time that an item takes to cook. We simply use the default - 10 seconds (200 ticks) Furnace->SetCookTimes(200, ct); } - // Restart cooking: Furnace->ContinueCooking(); + Furnace->SetLoading(false); return Furnace.release(); } diff --git a/src/main.cpp b/src/main.cpp index 5cd057278..2103f3356 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,7 +39,7 @@ bool cRoot::m_RunAsService = false; #if defined(_WIN32) - SERVICE_STATUS_HANDLE g_StatusHandle = NULL; + SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; HANDLE g_ServiceThread = INVALID_HANDLE_VALUE; #define SERVICE_NAME "MCServerService" #endif @@ -145,7 +145,7 @@ Its purpose is to create the crashdump using the dbghlp DLLs */ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo) { - char * newStack = &g_ExceptionStack[sizeof(g_ExceptionStack)]; + char * newStack = &g_ExceptionStack[sizeof(g_ExceptionStack) - 1]; char * oldStack; // Use the substitute stack: @@ -249,7 +249,8 @@ void universalMain(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo) -#if defined(_WIN32) + +#if defined(_WIN32) // Windows service support. //////////////////////////////////////////////////////////////////////////////// // serviceWorkerThread: Keep the service alive @@ -266,6 +267,7 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam) + //////////////////////////////////////////////////////////////////////////////// // serviceSetState: Set the internal status of the service @@ -319,14 +321,10 @@ void WINAPI serviceCtrlHandler(DWORD CtrlCode) void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) { - #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP) - Sleep(10000); - #endif - char applicationFilename[MAX_PATH]; char applicationDirectory[MAX_PATH]; - GetModuleFileName(NULL, applicationFilename, sizeof(applicationFilename)); // This binary's file path. + GetModuleFileName(nullptr, applicationFilename, sizeof(applicationFilename)); // This binary's file path. // Strip off the filename, keep only the path: strncpy_s(applicationDirectory, sizeof(applicationDirectory), applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename)); @@ -337,8 +335,7 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) SetCurrentDirectory(applicationDirectory); g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler); - - if (g_StatusHandle == NULL) + if (g_StatusHandle == nullptr) { OutputDebugStringA("RegisterServiceCtrlHandler() failed\n"); serviceSetState(0, SERVICE_STOPPED, GetLastError()); @@ -347,8 +344,9 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0); - g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL); - if (g_ServiceThread == NULL) + DWORD ThreadID; + g_ServiceThread = CreateThread(nullptr, 0, serviceWorkerThread, nullptr, 0, &ThreadID); + if (g_ServiceThread == nullptr) { OutputDebugStringA("CreateThread() failed\n"); serviceSetState(0, SERVICE_STOPPED, GetLastError()); @@ -360,7 +358,9 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) serviceSetState(0, SERVICE_STOPPED, 0); } -#endif +#endif // Windows service support. + + @@ -368,42 +368,33 @@ std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) { try { + // Parse the comand line args: TCLAP::CmdLine cmd("MCServer"); - - TCLAP::ValueArg<int> slotsArg("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); - - TCLAP::MultiArg<int> portsArg("p", "port", "The port number the server should listen to", false, "port", cmd); - - TCLAP::SwitchArg commLogArg("", "log-comm", "Log server client communications to file", cmd); - - TCLAP::SwitchArg commLogInArg("", "log-comm-in", "Log inbound server client communications to file", cmd); - - TCLAP::SwitchArg commLogOutArg("", "log-comm-out", "Log outbound server client communications to file", cmd); - - TCLAP::SwitchArg noBufArg("", "no-output-buffering", "Disable output buffering", cmd); - + TCLAP::ValueArg<int> slotsArg ("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); + TCLAP::MultiArg<int> portsArg ("p", "port", "The port number the server should listen to", false, "port", cmd); + TCLAP::SwitchArg commLogArg ("", "log-comm", "Log server client communications to file", cmd); + TCLAP::SwitchArg commLogInArg ("", "log-comm-in", "Log inbound server client communications to file", cmd); + TCLAP::SwitchArg commLogOutArg ("", "log-comm-out", "Log outbound server client communications to file", cmd); + TCLAP::SwitchArg crashDumpFull ("", "crash-dump-full", "Crashdumps created by the server will contain full server memory", cmd); + TCLAP::SwitchArg crashDumpGlobals("", "crash-dump-globals", "Crashdumps created by the server will contain the global variables' values", cmd); + TCLAP::SwitchArg noBufArg ("", "no-output-buffering", "Disable output buffering", cmd); + TCLAP::SwitchArg runAsServiceArg ("d", "service", "Run as a service on Windows, or daemon on UNIX like systems", cmd); cmd.parse(argc, argv); + // Copy the parsed args' values into a settings repository: auto repo = cpp14::make_unique<cMemorySettingsRepository>(); - if (slotsArg.isSet()) { - int slots = slotsArg.getValue(); - repo->AddValue("Server", "MaxPlayers", static_cast<Int64>(slots)); - } - if (portsArg.isSet()) { - std::vector<int> ports = portsArg.getValue(); - for (auto port : ports) + for (auto port: portsArg.getValue()) { repo->AddValue("Server", "Port", static_cast<Int64>(port)); } } - if (commLogArg.getValue()) { g_ShouldLogCommIn = true; @@ -414,120 +405,133 @@ std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) g_ShouldLogCommIn = commLogInArg.getValue(); g_ShouldLogCommOut = commLogOutArg.getValue(); } - if (noBufArg.getValue()) { setvbuf(stdout, nullptr, _IONBF, 0); } - repo->SetReadOnly(); + // Set the service flag directly to cRoot: + if (runAsServiceArg.getValue()) + { + cRoot::m_RunAsService = true; + } + + // Apply the CrashDump flags for platforms that support them: + #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC + if (crashDumpGlobals.getValue()) + { + g_DumpFlags = static_cast<MINIDUMP_TYPE>(g_DumpFlags | MiniDumpWithDataSegs); + } + if (crashDumpFull.getValue()) + { + g_DumpFlags = static_cast<MINIDUMP_TYPE>(g_DumpFlags | MiniDumpWithFullMemory); + } + #endif // 32-bit Windows app compiled in MSVC + return repo; } - catch (TCLAP::ArgException &e) + catch (const TCLAP::ArgException & exc) { - printf("error reading command line %s for arg %s", e.error().c_str(), e.argId().c_str()); + printf("Error reading command line %s for arg %s", exc.error().c_str(), exc.argId().c_str()); return cpp14::make_unique<cMemorySettingsRepository>(); } } + + + //////////////////////////////////////////////////////////////////////////////// // main: int main(int argc, char **argv) { - #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - InitLeakFinder(); + InitLeakFinder(); #endif // Magic code to produce dump-files on Windows if the server crashes: - #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) - HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL"); - g_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if (g_WriteMiniDump != nullptr) - { - _snprintf_s(g_DumpFileName, ARRAYCOUNT(g_DumpFileName), _TRUNCATE, "crash_mcs_%x.dmp", GetCurrentProcessId()); - SetUnhandledExceptionFilter(LastChanceExceptionFilter); - - // Parse arguments for minidump flags: - for (int i = 0; i < argc; i++) + #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC + HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL"); + g_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); + if (g_WriteMiniDump != nullptr) { - if (_stricmp(argv[i], "/cdg") == 0) - { - // Add globals to the dump - g_DumpFlags = (MINIDUMP_TYPE)(g_DumpFlags | MiniDumpWithDataSegs); - } - else if (_stricmp(argv[i], "/cdf") == 0) - { - // Add full memory to the dump (HUUUGE file) - g_DumpFlags = (MINIDUMP_TYPE)(g_DumpFlags | MiniDumpWithFullMemory); - } - } // for i - argv[] - } - #endif // _WIN32 && !_WIN64 + _snprintf_s(g_DumpFileName, ARRAYCOUNT(g_DumpFileName), _TRUNCATE, "crash_mcs_%x.dmp", GetCurrentProcessId()); + SetUnhandledExceptionFilter(LastChanceExceptionFilter); + } + #endif // 32-bit Windows app compiled in MSVC // End of dump-file magic + #if defined(_DEBUG) && defined(_MSC_VER) - _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - // _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output) - // Only useful when the leak is in the same sequence all the time - // _CrtSetBreakAlloc(85950); + // _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output) + // Only useful when the leak is in the same sequence all the time + // _CrtSetBreakAlloc(85950); #endif // _DEBUG && _MSC_VER #ifndef _DEBUG - std::signal(SIGSEGV, NonCtrlHandler); - std::signal(SIGTERM, NonCtrlHandler); - std::signal(SIGINT, NonCtrlHandler); - std::signal(SIGABRT, NonCtrlHandler); - #ifdef SIGABRT_COMPAT - std::signal(SIGABRT_COMPAT, NonCtrlHandler); - #endif // SIGABRT_COMPAT + std::signal(SIGSEGV, NonCtrlHandler); + std::signal(SIGTERM, NonCtrlHandler); + std::signal(SIGINT, NonCtrlHandler); + std::signal(SIGABRT, NonCtrlHandler); + #ifdef SIGABRT_COMPAT + std::signal(SIGABRT_COMPAT, NonCtrlHandler); + #endif // SIGABRT_COMPAT #endif - // DEBUG: test the dumpfile creation: - // *((int *)0) = 0; - auto argsRepo = parseArguments(argc, argv); - - // Check if comm logging is to be enabled: - for (int i = 0; i < argc; i++) - { - AString Arg(argv[i]); - if (NoCaseCompare(Arg, "/service") == 0) - { - cRoot::m_RunAsService = true; - } - } // for i - argv[] - #if defined(_WIN32) // Attempt to run as a service if (cRoot::m_RunAsService) { - SERVICE_TABLE_ENTRY ServiceTable[] = - { - { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, - { NULL, NULL } - }; + #if defined(_WIN32) // Windows service. + SERVICE_TABLE_ENTRY ServiceTable[] = + { + { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, + { nullptr, nullptr } + }; - if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) - { - LOGERROR("Attempted, but failed, service startup."); - return GetLastError(); - } + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) + { + LOGERROR("Attempted, but failed, service startup."); + return GetLastError(); + } + #else // UNIX daemon. + pid_t pid = fork(); + + // fork() returns a negative value on error. + if (pid < 0) + { + LOGERROR("Could not fork process."); + return EXIT_FAILURE; + } + + // Check if we are the parent or child process. Parent stops here. + if (pid > 0) + { + return EXIT_SUCCESS; + } + + // Child process now goes quiet, running in the background. + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + universalMain(std::move(argsRepo)); + #endif } else - #endif { // Not running as a service, do normal startup universalMain(std::move(argsRepo)); } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - DeinitLeakFinder(); + DeinitLeakFinder(); #endif return EXIT_SUCCESS; |