diff options
Diffstat (limited to 'src')
109 files changed, 1846 insertions, 972 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index e9a5ea0c6..2d0300ebf 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -1,8 +1,6 @@ $#include "../Globals.h" -$#include "tolua_base.h" - // Typedefs from Globals.h, so that we don't have to process that file: typedef long long Int64; typedef int Int32; @@ -14,6 +12,7 @@ typedef unsigned short UInt16; $cfile "../ChunkDef.h" +$cfile "../BiomeDef.h" $cfile "../../lib/inifile/iniFile.h" diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 41c641d9d..50b81e42a 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -2,17 +2,22 @@ cmake_minimum_required (VERSION 2.6) project (MCServer) +# NOTE: This CMake file is processed only for Unix builds; Windows(MSVC) builds handle all the subfolders in /src in a single file, /src/CMakeLists.txt + include_directories ("${PROJECT_SOURCE_DIR}/../") - ADD_CUSTOM_COMMAND( -#add any new generated bindings here - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Bindings.cpp ${CMAKE_CURRENT_BINARY_DIR}/Bindings.h -#command execuded to regerate bindings - COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg -#add any new generation dependencies here - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/virtual_method_hooks.lua ${CMAKE_CURRENT_SOURCE_DIR}/AllToLua.pkg tolua - ) - +ADD_CUSTOM_COMMAND( + # add any new generated bindings here + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.h + + # command execuded to regerate bindings + COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + + # add any new generation dependencies here + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/virtual_method_hooks.lua ${CMAKE_CURRENT_SOURCE_DIR}/AllToLua.pkg tolua +) + #add cpp files here add_library(Bindings PluginManager LuaState WebPlugin Bindings ManualBindings LuaWindow Plugin PluginLua WebPlugin) diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 64a818a60..149c304ed 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -228,6 +228,9 @@ bool cLuaState::PushFunction(const char * a_FunctionName) return false; } + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + lua_getglobal(m_LuaState, a_FunctionName); if (!lua_isfunction(m_LuaState, -1)) { @@ -249,6 +252,9 @@ bool cLuaState::PushFunction(int a_FnRef) ASSERT(IsValid()); ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref() if (!lua_isfunction(m_LuaState, -1)) { @@ -264,27 +270,29 @@ bool cLuaState::PushFunction(int a_FnRef) -bool cLuaState::PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName) +bool cLuaState::PushFunction(const cTableRef & a_TableRef) { ASSERT(IsValid()); ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack - - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef); // Get the table ref + + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef.GetTableRef()); // Get the table ref if (!lua_istable(m_LuaState, -1)) { // Not a table, bail out lua_pop(m_LuaState, 1); return false; } - lua_getfield(m_LuaState, -1, a_FnName); + lua_getfield(m_LuaState, -1, a_TableRef.GetFnName()); if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1)) { // Not a valid function, bail out lua_pop(m_LuaState, 2); return false; } - lua_remove(m_LuaState, -2); // Remove the table ref from the stack - m_CurrentFunctionName = "<table_callback>"; + Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName()); m_NumCurrentFunctionArgs = 0; return true; } @@ -297,7 +305,7 @@ void cLuaState::Push(const AString & a_String) { ASSERT(IsValid()); - tolua_pushcppstring(m_LuaState, a_String); + lua_pushlstring(m_LuaState, a_String.data(), a_String.size()); m_NumCurrentFunctionArgs += 1; } @@ -468,6 +476,18 @@ void cLuaState::Push(cItems * a_Items) +void cLuaState::Push(const cItems & a_Items) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, (void *)&a_Items, "cItems"); + m_NumCurrentFunctionArgs += 1; +} + + + + + void cLuaState::Push(cClientHandle * a_Client) { ASSERT(IsValid()); @@ -720,11 +740,13 @@ void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal) bool cLuaState::CallFunction(int a_NumResults) { ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first - ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); + ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); // The function to call + ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 2)); // The error handler - int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, 0); - if (ReportErrors(s)) + int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, -m_NumCurrentFunctionArgs - 2); + if (s != 0) { + // The error has already been printed together with the stacktrace LOGWARNING("Error in %s calling function %s()", m_SubsystemName.c_str(), m_CurrentFunctionName.c_str()); m_NumCurrentFunctionArgs = -1; m_CurrentFunctionName.clear(); @@ -952,15 +974,24 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status) void cLuaState::LogStackTrace(void) { + LogStackTrace(m_LuaState); +} + + + + + +void cLuaState::LogStackTrace(lua_State * a_LuaState) +{ LOGWARNING("Stack trace:"); lua_Debug entry; int depth = 0; - while (lua_getstack(m_LuaState, depth, &entry)) + while (lua_getstack(a_LuaState, depth, &entry)) { - int status = lua_getinfo(m_LuaState, "Sln", &entry); + int status = lua_getinfo(a_LuaState, "Sln", &entry); assert(status); - LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); + LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "(no name)"); depth++; } LOGWARNING("Stack trace end"); @@ -993,6 +1024,17 @@ AString cLuaState::GetTypeText(int a_StackPos) +int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) +{ + LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); + LogStackTrace(a_LuaState); + return 1; // We left the error message on the stack as the return value +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 15b0cdeff..a43d39732 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -85,6 +85,23 @@ public: } ; + /** Used for calling functions stored in a reference-stored table */ + class cTableRef + { + int m_TableRef; + const char * m_FnName; + public: + cTableRef(int a_TableRef, const char * a_FnName) : + m_TableRef(a_TableRef), + m_FnName(a_FnName) + { + } + + int GetTableRef(void) const { return m_TableRef; } + const char * GetFnName(void) const { return m_FnName; } + } ; + + /// A dummy class that's used only to delimit function args from return values for cLuaState::Call() class cRet { @@ -133,24 +150,6 @@ public: /// Returns true if a_FunctionName is a valid Lua function that can be called bool HasFunction(const char * a_FunctionName); - /** Pushes the function of the specified name onto the stack. - Returns true if successful. Logs a warning on failure (incl. m_SubsystemName) - */ - bool PushFunction(const char * a_FunctionName); - - /** Pushes a function that has been saved into the global registry, identified by a_FnRef. - Returns true if successful. Logs a warning on failure - */ - bool PushFunction(int a_FnRef); - - /** Pushes a function that is stored in a table ref. - Returns true if successful, false on failure. Doesn't log failure. - */ - bool PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName); - - /// Pushes a usertype of the specified class type onto the stack - void PushUserType(void * a_Object, const char * a_Type); - // Push a value onto the stack void Push(const AString & a_String); void Push(const AStringVector & a_Vector); @@ -165,6 +164,7 @@ public: void Push(cMonster * a_Monster); void Push(cItem * a_Item); void Push(cItems * a_Items); + void Push(const cItems & a_Items); void Push(cClientHandle * a_ClientHandle); void Push(cPickup * a_Pickup); void Push(cChunkDesc * a_ChunkDesc); @@ -182,7 +182,7 @@ public: void Push(void * a_Ptr); void Push(cHopperEntity * a_Hopper); void Push(cBlockEntity * a_BlockEntity); - + /// Call any 0-param 0-return Lua function in a single line: template <typename FnT> bool Call(FnT a_FnName) @@ -240,12 +240,33 @@ public: return CallFunction(0); } + /// Call any 0-param 1-return Lua function in a single line: + template< + typename FnT, typename RetT1 + > + bool Call(FnT a_FnName, const cRet & a_Mark, RetT1 & a_Ret1) + { + UNUSED(a_Mark); + if (!PushFunction(a_FnName)) + { + return false; + } + if (!CallFunction(1)) + { + return false; + } + GetReturn(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; + } + /// Call any 1-param 1-return Lua function in a single line: template< typename FnT, typename ArgT1, typename RetT1 > bool Call(FnT a_FnName, ArgT1 a_Arg1, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -266,6 +287,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -287,6 +309,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -309,6 +332,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -332,6 +356,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -357,6 +382,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -383,6 +409,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -410,6 +437,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, ArgT8 a_Arg8, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -438,6 +466,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, ArgT8 a_Arg8, ArgT9 a_Arg9, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -467,6 +496,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, ArgT8 a_Arg8, ArgT9 a_Arg9, ArgT10 a_Arg10, const cRet & a_Mark, RetT1 & a_Ret1) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -496,6 +526,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -517,6 +548,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -540,6 +572,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -564,6 +597,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -589,6 +623,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -616,6 +651,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -644,6 +680,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -673,6 +710,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -703,6 +741,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, ArgT8 a_Arg8, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -734,6 +773,7 @@ public: > bool Call(FnT a_FnName, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3, ArgT4 a_Arg4, ArgT5 a_Arg5, ArgT6 a_Arg6, ArgT7 a_Arg7, ArgT8 a_Arg8, ArgT9 a_Arg9, const cRet & a_Mark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3, RetT4 & a_Ret4, RetT5 & a_Ret5) { + UNUSED(a_Mark); if (!PushFunction(a_FnName)) { return false; @@ -761,25 +801,6 @@ public: } - /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, bool & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, AString & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, int & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, double & a_ReturnedVal); - - /** - Calls the function that has been pushed onto the stack by PushFunction(), - with arguments pushed by PushXXX(). - Returns true if successful, logs a warning on failure. - */ - bool CallFunction(int a_NumReturnValues); - /// Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1); @@ -807,6 +828,9 @@ public: /// Logs all items in the current stack trace to the server console void LogStackTrace(void); + /// Logs all items in the current stack trace to the server console + static void LogStackTrace(lua_State * a_LuaState); + /// Returns the type of the item on the specified position in the stack AString GetTypeText(int a_StackPos); @@ -826,6 +850,47 @@ protected: /// Number of arguments currently pushed (for the Push / Call chain) int m_NumCurrentFunctionArgs; + + + /** Pushes the function of the specified name onto the stack. + Returns true if successful. Logs a warning on failure (incl. m_SubsystemName) + */ + bool PushFunction(const char * a_FunctionName); + + /** Pushes a function that has been saved into the global registry, identified by a_FnRef. + Returns true if successful. Logs a warning on failure + */ + bool PushFunction(int a_FnRef); + + /** Pushes a function that is stored in a referenced table by name + Returns true if successful. Logs a warning on failure + */ + bool PushFunction(const cTableRef & a_TableRef); + + /// Pushes a usertype of the specified class type onto the stack + void PushUserType(void * a_Object, const char * a_Type); + + /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, bool & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, AString & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, int & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, double & a_ReturnedVal); + + /** + Calls the function that has been pushed onto the stack by PushFunction(), + with arguments pushed by PushXXX(). + Returns true if successful, logs a warning on failure. + */ + bool CallFunction(int a_NumReturnValues); + + /** Used as the error reporting function for function calls */ + static int ReportFnCallErrors(lua_State * a_LuaState); } ; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 2e19c2581..a9368f613 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -991,7 +991,6 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins(); lua_newtable(tolua_S); - int newTable = lua_gettop(tolua_S); int index = 1; cPluginManager::PluginMap::const_iterator iter = AllPlugins.begin(); while (iter != AllPlugins.end()) @@ -1137,16 +1136,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 +1161,11 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) } ParamIdx += 1; } + else if (tolua_isusertable(S, 1, "cPluginManager", 0, &err)) + { + // Style 1, use the global PlgMgr, but increment ParamIdx + ParamIdx++; + } if (lua_isnumber(S, ParamIdx) && lua_isfunction(S, ParamIdx + 1)) { @@ -1177,7 +1182,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; } @@ -1877,7 +1882,6 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) const cWebPlugin::TabNameList & TabNames = self->GetTabNames(); lua_newtable(tolua_S); - int newTable = lua_gettop(tolua_S); int index = 1; cWebPlugin::TabNameList::const_iterator iter = TabNames.begin(); while(iter != TabNames.end()) @@ -1898,6 +1902,35 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) +static int tolua_cClientHandle_SendPluginMessage(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserType(1, "cClientHandle") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + cClientHandle * Client = (cClientHandle *)tolua_tousertype(L, 1, NULL); + if (Client == NULL) + { + LOGWARNING("ClientHandle is nil in cClientHandle:SendPluginMessage()"); + S.LogStackTrace(); + return 0; + } + AString Channel, Message; + Channel.assign(lua_tostring(L, 2), lua_strlen(L, 2)); + Message.assign(lua_tostring(L, 3), lua_strlen(L, 3)); + Client->SendPluginMessage(Channel, Message); + return 0; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -1947,118 +1980,72 @@ public: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnNextBlock"), + a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - m_LuaState.Push(a_BlockType); - m_LuaState.Push(a_BlockMeta); - m_LuaState.Push(a_EntryFace); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnNextBlockNoData"), + a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - m_LuaState.Push(a_EntryFace); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnOutOfWorld")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnOutOfWorld"), + a_BlockX, a_BlockY, a_BlockZ, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnIntoWorld")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnIntoWorld"), + a_BlockX, a_BlockY, a_BlockZ, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual void OnNoMoreHits(void) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoMoreHits")) - { - // No such function in the table, skip the callback - return; - } - m_LuaState.CallFunction(0); + m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoMoreHits")); } virtual void OnNoChunk(void) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoChunk")) - { - // No such function in the table, skip the callback - return; - } - m_LuaState.CallFunction(0); + m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoChunk")); } protected: @@ -2286,6 +2273,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cClientHandle"); tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 9a3c2383e..f4a117721 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -68,6 +68,8 @@ public: virtual bool OnPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerEating (cPlayer & a_Player) = 0; + virtual bool OnPlayerFished (cPlayer & a_Player, const cItems & a_Reward) = 0; + virtual bool OnPlayerFishing (cPlayer & a_Player, cItems & a_Reward) = 0; virtual bool OnPlayerJoined (cPlayer & a_Player) = 0; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) = 0; virtual bool OnPlayerMoved (cPlayer & a_Player) = 0; @@ -82,6 +84,8 @@ public: virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; + virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) = 0; + virtual bool OnPluginsLoaded (void) = 0; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 0e5a66cd6..eefcd2b09 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -90,6 +90,8 @@ bool cPluginLua::Initialize(void) // Load all files for this plugin, and execute them AStringVector Files = cFile::GetFolderContents(PluginPath.c_str()); + + int numFiles = 0; for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if (itr->rfind(".lua") == AString::npos) @@ -101,9 +103,20 @@ bool cPluginLua::Initialize(void) { Close(); return false; + } + else + { + numFiles++; } } // for itr - Files[] + if (numFiles == 0) + { + LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str()); + Close(); + return false; + } + // Call intialize function bool res = false; if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res)) @@ -630,6 +643,46 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player) +bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_Reward, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_Reward, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); @@ -910,6 +963,44 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block +bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnPluginsLoaded(void) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + bool ret = false; + m_LuaState.Call((int)(**itr), cLuaState::Return, ret); + res = res || ret; + } + return res; +} + + + + + bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { cCSLock Lock(m_CriticalSection); @@ -1324,6 +1415,8 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_PLAYER_USED_ITEM: return "OnPlayerUsedItem"; case cPluginManager::HOOK_PLAYER_USING_BLOCK: return "OnPlayerUsingBlock"; case cPluginManager::HOOK_PLAYER_USING_ITEM: return "OnPlayerUsingItem"; + case cPluginManager::HOOK_PLUGIN_MESSAGE: return "OnPluginMessage"; + case cPluginManager::HOOK_PLUGINS_LOADED: return "OnPluginsLoaded"; case cPluginManager::HOOK_POST_CRAFTING: return "OnPostCrafting"; case cPluginManager::HOOK_PRE_CRAFTING: return "OnPreCrafting"; case cPluginManager::HOOK_SPAWNED_ENTITY: return "OnSpawnedEntity"; @@ -1337,8 +1430,17 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_WEATHER_CHANGED: return "OnWeatherChanged"; case cPluginManager::HOOK_WEATHER_CHANGING: return "OnWeatherChanging"; case cPluginManager::HOOK_WORLD_TICK: return "OnWorldTick"; - default: return NULL; + + case cPluginManager::HOOK_NUM_HOOKS: + { + // Satisfy a warning that all enum values should be used in a switch + // but don't want a default branch, so that we catch new hooks missing from this list. + break; + } } // switch (a_Hook) + LOGWARNING("Requested name of an unknown hook type function: %d (max is %d)", a_HookType, cPluginManager::HOOK_MAX); + ASSERT(!"Unknown hook requested!"); + return NULL; } diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index e1e274c72..c01f5ca89 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -65,6 +65,8 @@ public: virtual bool OnPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerEating (cPlayer & a_Player) override; + virtual bool OnPlayerFished (cPlayer & a_Player, const cItems & a_Reward) override; + virtual bool OnPlayerFishing (cPlayer & a_Player, cItems & a_Reward) override; virtual bool OnPlayerJoined (cPlayer & a_Player) override; virtual bool OnPlayerMoved (cPlayer & a_Player) override; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override; @@ -79,6 +81,8 @@ public: virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; + virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) override; + virtual bool OnPluginsLoaded (void) override; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 832dc4249..68e6aea33 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -118,7 +118,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) int KeyNum = a_SettingsIni.FindKey("Plugins"); // If it does, how many plugins are there? - unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); + int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); if (KeyNum == -1) { @@ -126,7 +126,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) } else if (NumPlugins > 0) { - for(unsigned int i = 0; i < NumPlugins; i++) + for (int i = 0; i < NumPlugins; i++) { AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); if (ValueName.compare("Plugin") == 0) @@ -136,7 +136,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { if (m_Plugins.find(PluginFile) != m_Plugins.end()) { - LoadPlugin( PluginFile ); + LoadPlugin(PluginFile); } } } @@ -155,6 +155,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { LOG("-- Loaded 1 Plugin --"); } + CallHookPluginsLoaded(); } @@ -693,6 +694,48 @@ bool cPluginManager::CallHookPlayerEating(cPlayer & a_Player) +bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems a_Reward) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_FISHED); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnPlayerFished(a_Player, a_Reward)) + { + return true; + } + } + return false; +} + + + + + +bool cPluginManager::CallHookPlayerFishing(cPlayer & a_Player, cItems a_Reward) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_FISHING); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnPlayerFishing(a_Player, a_Reward)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookPlayerJoined(cPlayer & a_Player) { HookMap::iterator Plugins = m_Hooks.find(HOOK_PLAYER_JOINED); @@ -987,6 +1030,46 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i +bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGIN_MESSAGE); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnPluginMessage(a_Client, a_Channel, a_Message)) + { + return true; + } + } + return false; +} + + + + + +bool cPluginManager::CallHookPluginsLoaded(void) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGINS_LOADED); + if (Plugins == m_Hooks.end()) + { + return false; + } + bool res = false; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + res = !(*itr)->OnPluginsLoaded() || res; + } + return res; +} + + + + + bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { HookMap::iterator Plugins = m_Hooks.find(HOOK_POST_CRAFTING); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 04d6470c7..9936f5a35 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -80,6 +80,8 @@ public: // tolua_export HOOK_PLAYER_BREAKING_BLOCK, HOOK_PLAYER_BROKEN_BLOCK, HOOK_PLAYER_EATING, + HOOK_PLAYER_FISHED, + HOOK_PLAYER_FISHING, HOOK_PLAYER_JOINED, HOOK_PLAYER_LEFT_CLICK, HOOK_PLAYER_MOVING, @@ -94,6 +96,8 @@ public: // tolua_export HOOK_PLAYER_USED_ITEM, HOOK_PLAYER_USING_BLOCK, HOOK_PLAYER_USING_ITEM, + HOOK_PLUGIN_MESSAGE, + HOOK_PLUGINS_LOADED, HOOK_POST_CRAFTING, HOOK_PRE_CRAFTING, HOOK_SPAWNED_ENTITY, @@ -167,6 +171,8 @@ public: // tolua_export bool CallHookPlayerBreakingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerEating (cPlayer & a_Player); + bool CallHookPlayerFished (cPlayer & a_Player, const cItems a_Reward); + bool CallHookPlayerFishing (cPlayer & a_Player, cItems a_Reward); bool CallHookPlayerJoined (cPlayer & a_Player); bool CallHookPlayerMoving (cPlayer & a_Player); bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); @@ -181,6 +187,8 @@ public: // tolua_export bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); + bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message); + bool CallHookPluginsLoaded (void); bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); @@ -271,7 +279,7 @@ private: bool m_bReloadPlugins; cPluginManager(); - ~cPluginManager(); + virtual ~cPluginManager(); /// Reloads all plugins, defaulting to settings.ini for settings location void ReloadPluginsNow(void); diff --git a/src/Bindings/tolua++.h b/src/Bindings/tolua++.h index 4dfd06318..73e65b746 100644 --- a/src/Bindings/tolua++.h +++ b/src/Bindings/tolua++.h @@ -2,12 +2,18 @@ // tolua++.h // Redirection file, needed because ToLua++ generates the Bindings.cpp file with >> #include "tolua++.h" << +// Only used from Bindings.cpp #include "tolua++/include/tolua++.h" +#ifdef _MSC_VER + // Disable specific warnings for the generated Bindings.cpp file: + #pragma warning(disable: 4800) // 'int' : forcing value to bool 'true' or 'false' (performance warning) +#endif // _MSC_VER + diff --git a/src/Bindings/tolua_base.h b/src/Bindings/tolua_base.h deleted file mode 100644 index 6a76f97b1..000000000 --- a/src/Bindings/tolua_base.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef TOLUA_BASE_H -#define TOLUA_BASE_H - -#pragma warning(disable:4800) // This file is ONLY included by Bindings.cpp and it throws lots of C4800 warnings - -#include "tolua++/include/tolua++.h" - - - - - -class ToluaBase { - - int lua_instance; - -protected: - - lua_State* lua_state; - - void lua_stacktrace(lua_State* L) const - { - lua_Debug entry; - int depth = 0; - - while (lua_getstack(L, depth, &entry)) - { - lua_getinfo(L, "Sln", &entry); - - LOGERROR("%s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); - depth++; - } - } - - - bool report_errors(int status) const - { - if ( status!=0 ) - { - const char* s = lua_tostring(lua_state, -1); - LOGERROR("-- %s", s ); - //lua_pop(lua_state, 1); - LOGERROR("Stack:"); - lua_stacktrace( lua_state ); - return true; - } - return false; - } - - bool push_method(const char* name, lua_CFunction f) const { - - if (!lua_state) return false; - - lua_getref(lua_state, lua_instance); - lua_pushstring(lua_state, name); - //LOGINFO("1. push_method() Stack size: %i", lua_gettop( lua_state ) ); - lua_gettable(lua_state, -2); - //LOGINFO("2. push_method() Stack size: %i", lua_gettop( lua_state ) ); - - if (lua_isnil(lua_state, -1)) { - - // pop the table - lua_pop(lua_state, 2); - return false; - - } else { - - if (f) { - if (lua_iscfunction(lua_state, -1)) { - lua_pop(lua_state, 2); - return false; - }; - /* // not for now - lua_pushcfunction(lua_state, f); - if (lua_rawequal(lua_state, -1, -2)) { - - // avoid recursion, pop both functions and the table - lua_pop(lua_state, 3); - return false; - }; - - // pop f - lua_pop(lua_state, 1); - */ - }; - - // swap table with function - lua_insert(lua_state, -2); - }; - - return true; - }; - - void dbcall(lua_State* L, int nargs, int nresults) const { - - // using lua_call for now - int s = lua_pcall(L, nargs, nresults, 0); - report_errors( s ); - }; -public: - - int GetInstance() { return lua_instance; } - lua_State* GetLuaState() { return lua_state; } - - void tolua__set_instance(lua_State* L, lua_Object lo) { - - lua_state = L; - - lua_pushvalue(L, lo); - lua_instance = lua_ref(lua_state, 1); - }; - - ToluaBase() { - - lua_state = NULL; - }; - - ~ToluaBase() { - - if (lua_state) { - - lua_unref(lua_state, lua_instance); - }; - }; -}; - -#endif - - diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp new file mode 100644 index 000000000..89a1cdefb --- /dev/null +++ b/src/BiomeDef.cpp @@ -0,0 +1,131 @@ + +// BiomeDef.cpp + +// Implements biome helper functions + +#include "Globals.h" +#include "BiomeDef.h" + + +EMCSBiome StringToBiome(const AString & a_BiomeString) +{ + // If it is a number, return it: + int res = atoi(a_BiomeString.c_str()); + if ((res != 0) || (a_BiomeString.compare("0") == 0)) + { + // It was a valid number + return (EMCSBiome)res; + } + + // Convert using the built-in map: + static struct { + EMCSBiome m_Biome; + const char * m_String; + } BiomeMap[] = + { + {biOcean, "Ocean"} , + {biPlains, "Plains"}, + {biDesert, "Desert"}, + {biExtremeHills, "ExtremeHills"}, + {biForest, "Forest"}, + {biTaiga, "Taiga"}, + {biSwampland, "Swampland"}, + {biRiver, "River"}, + {biNether, "Hell"}, + {biNether, "Nether"}, + {biEnd, "Sky"}, + {biEnd, "End"}, + {biFrozenOcean, "FrozenOcean"}, + {biFrozenRiver, "FrozenRiver"}, + {biIcePlains, "IcePlains"}, + {biIcePlains, "Tundra"}, + {biIceMountains, "IceMountains"}, + {biMushroomIsland, "MushroomIsland"}, + {biMushroomShore, "MushroomShore"}, + {biBeach, "Beach"}, + {biDesertHills, "DesertHills"}, + {biForestHills, "ForestHills"}, + {biTaigaHills, "TaigaHills"}, + {biExtremeHillsEdge, "ExtremeHillsEdge"}, + {biJungle, "Jungle"}, + {biJungleHills, "JungleHills"}, + + // Release 1.7 biomes: + {biJungleEdge, "JungleEdge"}, + {biDeepOcean, "DeepOcean"}, + {biStoneBeach, "StoneBeach"}, + {biColdBeach, "ColdBeach"}, + {biBirchForest, "BirchForest"}, + {biBirchForestHills, "BirchForestHills"}, + {biRoofedForest, "RoofedForest"}, + {biColdTaiga, "ColdTaiga"}, + {biColdTaigaHills, "ColdTaigaHills"}, + {biMegaTaiga, "MegaTaiga"}, + {biMegaTaigaHills, "MegaTaigaHills"}, + {biExtremeHillsPlus, "ExtremeHillsPlus"}, + {biSavanna, "Savanna"}, + {biSavannaPlateau, "SavannaPlateau"}, + {biMesa, "Mesa"}, + {biMesaPlateauF, "MesaPlateauF"}, + {biMesaPlateau, "MesaPlateau"}, + + // Release 1.7 variants: + {biSunflowerPlains, "SunflowerPlains"}, + {biDesertM, "DesertM"}, + {biExtremeHillsM, "ExtremeHillsM"}, + {biFlowerForest, "FlowerForest"}, + {biTaigaM, "TaigaM"}, + {biSwamplandM, "SwamplandM"}, + {biIcePlainsSpikes, "IcePlainsSpikes"}, + {biJungleM, "JungleM"}, + {biJungleEdgeM, "JungleEdgeM"}, + {biBirchForestM, "BirchForestM"}, + {biBirchForestHillsM, "BirchForestHillsM"}, + {biRoofedForestM, "RoofedForestM"}, + {biColdTaigaM, "ColdTaigaM"}, + {biMegaSpruceTaiga, "MegaSpruceTaiga"}, + {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, + {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, + {biSavannaM, "SavannaM"}, + {biSavannaPlateauM, "SavannaPlateauM"}, + {biMesaBryce, "MesaBryce"}, + {biMesaPlateauFM, "MesaPlateauFM"}, + {biMesaPlateauM, "MesaPlateauM"}, + } ; + + for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++) + { + if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) + { + return BiomeMap[i].m_Biome; + } + } // for i - BiomeMap[] + return (EMCSBiome)-1; +} + + + + + +bool IsBiomeNoDownfall(EMCSBiome a_Biome) +{ + switch (a_Biome) + { + case biDesert: + case biDesertHills: + case biDesertM: + case biSavanna: + case biSavannaM: + case biSavannaPlateau: + case biSavannaPlateauM: + case biNether: + case biEnd: + { + return true; + } + default: + { + return false; + } + } +} diff --git a/src/BiomeDef.h b/src/BiomeDef.h new file mode 100644 index 000000000..df1e387f0 --- /dev/null +++ b/src/BiomeDef.h @@ -0,0 +1,107 @@ + +// BiomeDef.h + +// Defines relevant information and methods related to biomes + + + + + +#pragma once + + + + + +// tolua_begin +/** Biome IDs +The first batch corresponds to the clientside biomes, used by MineCraft. +BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client +*/ +enum EMCSBiome +{ + biOcean = 0, + biPlains = 1, + biDesert = 2, + biExtremeHills = 3, + biForest = 4, + biTaiga = 5, + biSwampland = 6, + biRiver = 7, + biHell = 8, // same as Nether + biNether = 8, + biSky = 9, // same as biEnd + biEnd = 9, + biFrozenOcean = 10, + biFrozenRiver = 11, + biIcePlains = 12, + biTundra = 12, // same as Ice Plains + biIceMountains = 13, + biMushroomIsland = 14, + biMushroomShore = 15, + biBeach = 16, + biDesertHills = 17, + biForestHills = 18, + biTaigaHills = 19, + biExtremeHillsEdge = 20, + biJungle = 21, + biJungleHills = 22, + + // Release 1.7 biomes: + biJungleEdge = 23, + biDeepOcean = 24, + biStoneBeach = 25, + biColdBeach = 26, + biBirchForest = 27, + biBirchForestHills = 28, + biRoofedForest = 29, + biColdTaiga = 30, + biColdTaigaHills = 31, + biMegaTaiga = 32, + biMegaTaigaHills = 33, + biExtremeHillsPlus = 34, + biSavanna = 35, + biSavannaPlateau = 36, + biMesa = 37, + biMesaPlateauF = 38, + biMesaPlateau = 39, + + // Automatically capture the maximum consecutive biome value into biMaxBiome: + biNumBiomes, // True number of biomes, since they are zero-based + biMaxBiome = biNumBiomes - 1, // The maximum biome value + + // Add this number to the biomes to get the variant + biVariant = 128, + + // Release 1.7 biome variants: + biSunflowerPlains = 129, + biDesertM = 130, + biExtremeHillsM = 131, + biFlowerForest = 132, + biTaigaM = 133, + biSwamplandM = 134, + biIcePlainsSpikes = 140, + biJungleM = 149, + biJungleEdgeM = 151, + biBirchForestM = 155, + biBirchForestHillsM = 156, + biRoofedForestM = 157, + biColdTaigaM = 158, + biMegaSpruceTaiga = 160, + biMegaSpruceTaigaHills = 161, + biExtremeHillsPlusM = 162, + biSavannaM = 163, + biSavannaPlateauM = 164, + biMesaBryce = 165, + biMesaPlateauFM = 166, + biMesaPlateauM = 167, +} ; + +/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure. +extern EMCSBiome StringToBiome(const AString & a_BiomeString); + +/// Returns true if the biome has no downfall - deserts and savannas +extern bool IsBiomeNoDownfall(EMCSBiome a_Biome); + + +// tolua_end diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 1148908c6..910661f60 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -28,6 +28,8 @@ template<typename Combinator> void InternalMergeBlocks( Combinator a_Combinator ) { + UNUSED(a_SrcSizeY); + UNUSED(a_DstSizeY); for (int y = 0; y < a_SizeY; y++) { int SrcBaseY = (y + a_SrcOffY) * a_SrcSizeX * a_SrcSizeZ; @@ -826,7 +828,7 @@ void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int int yd = dy - dx / 2; int zd = dz - dx / 2; - while (true) + for (;;) { RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); @@ -858,7 +860,7 @@ void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int int xd = dx - dy / 2; int zd = dz - dy / 2; - while (true) + for (;;) { RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); @@ -892,7 +894,7 @@ void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int int xd = dx - dz / 2; int yd = dy - dz / 2; - while (true) + for (;;) { RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 0d358b556..7c6688f8d 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -87,7 +87,11 @@ public: virtual void SendTo(cClientHandle & a_Client) = 0; /// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing. - virtual bool Tick(float a_Dt, cChunk & a_Chunk) { return false; } + virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) + { + UNUSED(a_Dt); + return false; + } protected: /// Position in absolute block coordinates diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h index f35412e03..bf6289a2f 100644 --- a/src/BlockEntities/BlockEntityWithItems.h +++ b/src/BlockEntities/BlockEntityWithItems.h @@ -73,6 +73,7 @@ protected: // cItemGrid::cListener overrides: virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) { + UNUSED(a_SlotNum); ASSERT(a_Grid == &m_Contents); if (m_World != NULL) { 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/FurnaceEntity.h b/src/BlockEntities/FurnaceEntity.h index 8b695d61a..b08187300 100644 --- a/src/BlockEntities/FurnaceEntity.h +++ b/src/BlockEntities/FurnaceEntity.h @@ -95,7 +95,7 @@ public: // tolua_end - void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned) {m_FuelBurnTime = a_FuelBurnTime; m_TimeBurned = 0; } + void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned) {m_FuelBurnTime = a_FuelBurnTime; m_TimeBurned = a_TimeBurned; } void SetCookTimes(int a_NeedCookTime, int a_TimeCooked) {m_NeedCookTime = a_NeedCookTime; m_TimeCooked = a_TimeCooked; } protected: 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/BlockEntities/JukeboxEntity.h b/src/BlockEntities/JukeboxEntity.h index fcafdc479..996de965b 100644 --- a/src/BlockEntities/JukeboxEntity.h +++ b/src/BlockEntities/JukeboxEntity.h @@ -45,7 +45,7 @@ public: // tolua_end virtual void UsedBy(cPlayer * a_Player) override; - virtual void SendTo(cClientHandle & a_Client) override { }; + virtual void SendTo(cClientHandle &) override { }; private: int m_Record; diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index e2d088f44..cf78aeac6 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -52,7 +52,7 @@ public: // tolua_end virtual void UsedBy(cPlayer * a_Player) override; - virtual void SendTo(cClientHandle & a_Client) override { }; + virtual void SendTo(cClientHandle &) override { }; private: char m_Pitch; diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 05d4c6595..b609af571 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -267,106 +267,6 @@ AString ItemToFullString(const cItem & a_Item) -EMCSBiome StringToBiome(const AString & a_BiomeString) -{ - // If it is a number, return it: - int res = atoi(a_BiomeString.c_str()); - if ((res != 0) || (a_BiomeString.compare("0") == 0)) - { - // It was a valid number - return (EMCSBiome)res; - } - - // Convert using the built-in map: - static struct { - EMCSBiome m_Biome; - const char * m_String; - } BiomeMap[] = - { - {biOcean, "Ocean"} , - {biPlains, "Plains"}, - {biDesert, "Desert"}, - {biExtremeHills, "ExtremeHills"}, - {biForest, "Forest"}, - {biTaiga, "Taiga"}, - {biSwampland, "Swampland"}, - {biRiver, "River"}, - {biNether, "Hell"}, - {biNether, "Nether"}, - {biEnd, "Sky"}, - {biEnd, "End"}, - {biFrozenOcean, "FrozenOcean"}, - {biFrozenRiver, "FrozenRiver"}, - {biIcePlains, "IcePlains"}, - {biIcePlains, "Tundra"}, - {biIceMountains, "IceMountains"}, - {biMushroomIsland, "MushroomIsland"}, - {biMushroomShore, "MushroomShore"}, - {biBeach, "Beach"}, - {biDesertHills, "DesertHills"}, - {biForestHills, "ForestHills"}, - {biTaigaHills, "TaigaHills"}, - {biExtremeHillsEdge, "ExtremeHillsEdge"}, - {biJungle, "Jungle"}, - {biJungleHills, "JungleHills"}, - - // Release 1.7 biomes: - {biJungleEdge, "JungleEdge"}, - {biDeepOcean, "DeepOcean"}, - {biStoneBeach, "StoneBeach"}, - {biColdBeach, "ColdBeach"}, - {biBirchForest, "BirchForest"}, - {biBirchForestHills, "BirchForestHills"}, - {biRoofedForest, "RoofedForest"}, - {biColdTaiga, "ColdTaiga"}, - {biColdTaigaHills, "ColdTaigaHills"}, - {biMegaTaiga, "MegaTaiga"}, - {biMegaTaigaHills, "MegaTaigaHills"}, - {biExtremeHillsPlus, "ExtremeHillsPlus"}, - {biSavanna, "Savanna"}, - {biSavannaPlateau, "SavannaPlateau"}, - {biMesa, "Mesa"}, - {biMesaPlateauF, "MesaPlateauF"}, - {biMesaPlateau, "MesaPlateau"}, - - // Release 1.7 variants: - {biSunflowerPlains, "SunflowerPlains"}, - {biDesertM, "DesertM"}, - {biExtremeHillsM, "ExtremeHillsM"}, - {biFlowerForest, "FlowerForest"}, - {biTaigaM, "TaigaM"}, - {biSwamplandM, "SwamplandM"}, - {biIcePlainsSpikes, "IcePlainsSpikes"}, - {biJungleM, "JungleM"}, - {biJungleEdgeM, "JungleEdgeM"}, - {biBirchForestM, "BirchForestM"}, - {biBirchForestHillsM, "BirchForestHillsM"}, - {biRoofedForestM, "RoofedForestM"}, - {biColdTaigaM, "ColdTaigaM"}, - {biMegaSpruceTaiga, "MegaSpruceTaiga"}, - {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, - {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, - {biSavannaM, "SavannaM"}, - {biSavannaPlateauM, "SavannaPlateauM"}, - {biMesaBryce, "MesaBryce"}, - {biMesaPlateauFM, "MesaPlateauFM"}, - {biMesaPlateauM, "MesaPlateauM"}, - } ; - - for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++) - { - if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) - { - return BiomeMap[i].m_Biome; - } - } // for i - BiomeMap[] - return (EMCSBiome)-1; -} - - - - - int StringToMobType(const AString & a_MobString) { static struct { diff --git a/src/BlockID.h b/src/BlockID.h index 288719ccf..899336fa6 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -876,9 +876,6 @@ extern AString ItemTypeToString(short a_ItemType); /// Translates a full item into a fully-specified string (including meta and count). If the ItemType is not recognized, the ItemType number is output into the string. extern AString ItemToFullString(const cItem & a_Item); -/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure. -extern EMCSBiome StringToBiome(const AString & a_BiomeString); - /// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT) extern int StringToMobType(const AString & a_MobString); diff --git a/src/BlockTracer.h b/src/BlockTracer.h index d0a34811d..40d80da1a 100644 --- a/src/BlockTracer.h +++ b/src/BlockTracer.h @@ -36,7 +36,14 @@ public: /** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded When this callback returns true, the tracing is aborted. */ - virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; } + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) + { + UNUSED(a_BlockX); + UNUSED(a_BlockY); + UNUSED(a_BlockZ); + UNUSED(a_EntryFace); + return false; + } /** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) The coords specify the exact point at which the path exited the world. @@ -44,7 +51,13 @@ public: Note that some paths can go out of the world and come back again (parabola), in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls */ - virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) { return false; } + virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) + { + UNUSED(a_BlockX); + UNUSED(a_BlockY); + UNUSED(a_BlockZ); + return false; + } /** Called when the path goes into the world, from either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) The coords specify the exact point at which the path entered the world. @@ -52,7 +65,13 @@ public: Note that some paths can go out of the world and come back again (parabola), in such a case this callback is followed by further OnNextBlock() calls */ - virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) { return false; } + virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) + { + UNUSED(a_BlockX); + UNUSED(a_BlockY); + UNUSED(a_BlockZ); + return false; + } /** Called when the path is sure not to hit any more blocks. Note that for some shapes this might never happen (line with constant Y) diff --git a/src/Blocks/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h index 5f0d95dee..6c198efc4 100644 --- a/src/Blocks/BlockGlowstone.h +++ b/src/Blocks/BlockGlowstone.h @@ -20,8 +20,8 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to 0 - // TODO: More drops? - a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, 1, 0)); + MTRand r1; + a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, (char)(2 + r1.randInt(2)), 0)); } } ; diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 107d36476..a732aa797 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -99,7 +99,11 @@ public: virtual bool DoesIgnoreBuildCollision(void); /// <summary>Similar to DoesIgnoreBuildCollision(void), but is used for cases where block meta/player item-in-hand is needed to determine collision (thin snow)</summary> - virtual bool DoesIgnoreBuildCollision(cPlayer * a_Player, NIBBLETYPE a_Meta) { return DoesIgnoreBuildCollision(); } + virtual bool DoesIgnoreBuildCollision(cPlayer *, NIBBLETYPE a_Meta) + { + UNUSED(a_Meta); + return DoesIgnoreBuildCollision(); + } /// <summary>Returns if this block drops if it gets destroyed by an unsuitable situation. Default: true</summary> virtual bool DoesDropOnUnsuitable(void); diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 64c03d0d3..e06f63a0e 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -773,7 +773,7 @@ void cByteBuffer::ReadAll(AString & a_Data) -bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, int a_NumBytes) +bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes) { if (!a_Dst.CanWriteBytes(a_NumBytes) || !CanReadBytes(a_NumBytes)) { @@ -781,9 +781,10 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, int a_NumBytes) return false; } char buf[1024]; - while (a_NumBytes > 0) + // > 0 without generating warnings about unsigned comparisons where size_t is unsigned + while (a_NumBytes != 0) { - int num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes; + size_t num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes; VERIFY(ReadBuf(buf, num)); VERIFY(a_Dst.Write(buf, num)); a_NumBytes -= num; diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 06c846fa9..cbce119b1 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -110,7 +110,7 @@ public: void ReadAll(AString & a_Data); /// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. - bool ReadToByteBuffer(cByteBuffer & a_Dst, int a_NumBytes); + bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes); /// Removes the bytes that have been read from the ringbuffer void CommitRead(void); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88e469b74..853138769 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities) -if (NOT WIN32) +if (NOT MSVC) foreach(folder ${FOLDERS}) add_subdirectory(${folder}) endforeach(folder) @@ -62,18 +62,25 @@ else () endif() -if (UNIX) - set(EXECUTABLE ../MCServer/MCServer) -else () - set(EXECUTABLE MCServer) -endif () - +set(EXECUTABLE MCServer) add_executable(${EXECUTABLE} ${SOURCE}) +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: + SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES PREFIX "../") + SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES IMPORT_PREFIX "../") +endif() + + +# Make the debug executable have a "_debug" suffix +SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES DEBUG_POSTFIX "_debug") + # Precompiled headers (2nd part) -if (WIN32) +if (MSVC) SET_TARGET_PROPERTIES( ${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/Yu\"Globals.h\"" OBJECT_DEPENDS "$(IntDir)/$(TargetName.pch)" @@ -81,7 +88,7 @@ if (WIN32) endif () -if (NOT WIN32) +if (NOT MSVC) target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks) target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage) target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index c446db9a6..fb26e983d 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -527,9 +527,11 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) // MG TODO : check that "Level" really means Y + /* NIBBLETYPE SkyLight = 0; NIBBLETYPE BlockLight = 0; + */ if (IsLightValid()) { @@ -2324,8 +2326,8 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock (m_BlockTypes, a_RelX, a_RelY, a_RelZ); - a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); + a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx); + a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx); } @@ -2898,10 +2900,6 @@ NIBBLETYPE cChunk::GetTimeAlteredLight(NIBBLETYPE a_Skylight) const -#if !C_CHUNK_USE_INLINE -# include "cChunk.inl.h" -#endif - diff --git a/src/Chunk.h b/src/Chunk.h index 05a96d419..f0a50c3c4 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -12,19 +12,6 @@ -#define C_CHUNK_USE_INLINE 1 - -// Do not touch -#if C_CHUNK_USE_INLINE - #define __C_CHUNK_INLINE__ inline -#else - #define __C_CHUNK_INLINE__ -#endif - - - - - namespace Json { class Value; @@ -436,8 +423,6 @@ private: void RemoveBlockEntity(cBlockEntity * a_BlockEntity); void AddBlockEntity (cBlockEntity * a_BlockEntity); - void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff); - /// Creates a block entity for each block that needs a block entity and doesn't have one in the list void CreateBlockEntities(void); @@ -482,11 +467,3 @@ typedef std::list<cChunkPtr> cChunkPtrList; - -#if C_CHUNK_USE_INLINE - #include "Chunk.inl.h" -#endif - - - - diff --git a/src/Chunk.inl.h b/src/Chunk.inl.h deleted file mode 100644 index fb9c4dad1..000000000 --- a/src/Chunk.inl.h +++ /dev/null @@ -1,34 +0,0 @@ - -#ifndef __C_CHUNK_INL_H__ -#define __C_CHUNK_INL_H__ - -#ifndef MAX -# define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - - - - - -__C_CHUNK_INLINE__ -void cChunk::SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff) -{ - unsigned char CurrentLight = cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y, a_Z ); - cChunkDef::SetNibble( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X-1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - cChunkDef::SetNibble( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X+1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - cChunkDef::SetNibble( a_LightBuffer, a_X, a_Y-1, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y-1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - cChunkDef::SetNibble( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y+1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - cChunkDef::SetNibble( a_LightBuffer, a_X, a_Y, a_Z-1, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y, a_Z-1 ), MAX(0,CurrentLight-a_Falloff) ) ); - cChunkDef::SetNibble( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y, a_Z+1 ), MAX(0,CurrentLight-a_Falloff) ) ); - MarkDirty(); -} - - - - - -#endif - - - - diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 8c37e7907..edeb7c0a0 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -10,6 +10,7 @@ #pragma once #include "Vector3i.h" +#include "BiomeDef.h" @@ -57,97 +58,6 @@ typedef unsigned char HEIGHTTYPE; - - -// tolua_begin -/** Biome IDs -The first batch corresponds to the clientside biomes, used by MineCraft. -BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client -*/ -enum EMCSBiome -{ - biOcean = 0, - biPlains = 1, - biDesert = 2, - biExtremeHills = 3, - biForest = 4, - biTaiga = 5, - biSwampland = 6, - biRiver = 7, - biHell = 8, // same as Nether - biNether = 8, - biSky = 9, // same as biEnd - biEnd = 9, - biFrozenOcean = 10, - biFrozenRiver = 11, - biIcePlains = 12, - biTundra = 12, // same as Ice Plains - biIceMountains = 13, - biMushroomIsland = 14, - biMushroomShore = 15, - biBeach = 16, - biDesertHills = 17, - biForestHills = 18, - biTaigaHills = 19, - biExtremeHillsEdge = 20, - biJungle = 21, - biJungleHills = 22, - - // Release 1.7 biomes: - biJungleEdge = 23, - biDeepOcean = 24, - biStoneBeach = 25, - biColdBeach = 26, - biBirchForest = 27, - biBirchForestHills = 28, - biRoofedForest = 29, - biColdTaiga = 30, - biColdTaigaHills = 31, - biMegaTaiga = 32, - biMegaTaigaHills = 33, - biExtremeHillsPlus = 34, - biSavanna = 35, - biSavannaPlateau = 36, - biMesa = 37, - biMesaPlateauF = 38, - biMesaPlateau = 39, - - // Automatically capture the maximum consecutive biome value into biMaxBiome: - biNumBiomes, // True number of biomes, since they are zero-based - biMaxBiome = biNumBiomes - 1, // The maximum biome value - - // Add this number to the biomes to get the variant - biVariant = 128, - - // Release 1.7 biome variants: - biSunflowerPlains = 129, - biDesertM = 130, - biExtremeHillsM = 131, - biFlowerForest = 132, - biTaigaM = 133, - biSwamplandM = 134, - biIcePlainsSpikes = 140, - biJungleM = 149, - biJungleEdgeM = 151, - biBirchForestM = 155, - biBirchForestHillsM = 156, - biRoofedForestM = 157, - biColdTaigaM = 158, - biMegaSpruceTaiga = 160, - biMegaSpruceTaigaHills = 161, - biExtremeHillsPlusM = 162, - biSavannaM = 163, - biSavannaPlateauM = 164, - biMesaBryce = 165, - biMesaPlateauFM = 166, - biMesaPlateauM = 167, -} ; - -// tolua_end - - - - /// Constants used throughout the code, useful typedefs and utility functions class cChunkDef { @@ -182,6 +92,7 @@ public: /// Converts absolute block coords into relative (chunk + block) coords: inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ ) { + UNUSED(a_Y); BlockToChunk(a_X, a_Z, a_ChunkX, a_ChunkZ); a_X = a_X - a_ChunkX * Width; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 86fbceff7..e14090b18 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -991,7 +991,7 @@ bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) { - while (true) + for (;;) { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index fe3ee9b42..2425adf18 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -264,7 +264,7 @@ void cChunkSender::BlockEntity(cBlockEntity * a_Entity) -void cChunkSender::Entity(cEntity * a_Entity) +void cChunkSender::Entity(cEntity *) { // Nothing needed yet, perhaps in the future when we save entities into chunks we'd like to send them upon load, too ;) } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 99df47bfb..9348a1825 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -543,6 +543,15 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, +void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) +{ + cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", @@ -1409,6 +1418,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size) void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) { + UNUSED(a_World); ASSERT(m_Player != NULL); if (a_SendRespawnPacket) @@ -1968,6 +1978,15 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) +void cClientHandle::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + m_Protocol->SendPluginMessage(a_Channel, a_Message); +} + + + + + void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { m_Protocol->SendRemoveEntityEffect(a_Entity, a_EffectID); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 26d5e74b7..297d62d57 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -120,6 +120,7 @@ public: void SendPlayerMoveLook (void); void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); + void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); void SendRespawn (void); void SendExperience (void); @@ -178,6 +179,7 @@ public: void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround); void HandlePlayerMoveLook (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround); // While m_bPositionConfirmed (normal gameplay) void HandlePlayerPos (double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround); + void HandlePluginMessage (const AString & a_Channel, const AString & a_Message); void HandleRespawn (void); void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem); void HandleSlotSelected (short a_SlotNum); diff --git a/src/CommandOutput.h b/src/CommandOutput.h index bdf675238..3763d625f 100644 --- a/src/CommandOutput.h +++ b/src/CommandOutput.h @@ -38,6 +38,7 @@ class cNullCommandOutputCallback : virtual void Out(const AString & a_Text) override { // Do nothing + UNUSED(a_Text); } } ; diff --git a/src/Defines.h b/src/Defines.h index 534802d55..c75effa44 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -563,34 +563,6 @@ namespace ItemCategory } } - - - - -/// Returns true if the biome has no downfall - deserts and savannas -inline bool IsBiomeNoDownfall(EMCSBiome a_Biome) -{ - switch (a_Biome) - { - case biDesert: - case biDesertHills: - case biDesertM: - case biSavanna: - case biSavannaM: - case biSavannaPlateau: - case biSavannaPlateauM: - case biNether: - case biEnd: - { - return true; - } - default: - { - return false; - } - } -} - // tolua_end diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 9cb36eb14..2ba1b303d 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -351,10 +351,14 @@ public: // tolua_end /// Called when the specified player right-clicks this entity - virtual void OnRightClicked(cPlayer & a_Player) {}; + virtual void OnRightClicked(cPlayer &) {}; /// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy(). - virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) {} + virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) + { + UNUSED(a_Drops); + UNUSED(a_Killer); + } protected: static cCriticalSection m_CSCount; @@ -420,11 +424,13 @@ protected: void Dereference( cEntity*& a_EntityPtr ); private: - // Measured in degrees (MAX 360°) + // Measured in degrees, [-180, +180) double m_HeadYaw; + // Measured in meter/second (m/s) Vector3d m_Speed; - // Measured in degrees (MAX 360°) + + // Measured in degrees, [-180, +180) Vector3d m_Rot; /// Position of the entity's XZ center and Y bottom diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 67d5a47ef..bc92790aa 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -908,8 +908,8 @@ bool cPlayer::IsGameModeSurvival(void) const bool cPlayer::IsGameModeAdventure(void) const { - return (m_GameMode == gmCreative) || // Either the player is explicitly in Adventure - ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Adventure + return (m_GameMode == gmAdventure) || // Either the player is explicitly in Adventure + ((m_GameMode == gmNotSet) && m_World->IsGameModeAdventure()); // or they inherit from the world and the world is Adventure } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 66f1c07a7..f9ce950ba 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -45,7 +45,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override { }; + virtual void HandlePhysics(float a_Dt, cChunk &) override { UNUSED(a_Dt); }; /// Returns the curently equipped weapon; empty item if none virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } @@ -114,7 +114,7 @@ public: double GetEyeHeight(void) const; // tolua_export Vector3d GetEyePosition(void) const; // tolua_export inline bool IsOnGround(void) const {return m_bTouchGround; } // tolua_export - inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc. + inline double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc. inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export inline const cInventory & GetInventory(void) const { return m_Inventory; } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 959e81ae5..4721409ee 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -52,7 +52,11 @@ public: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace); /// Called by the physics blocktracer when the entity hits another entity - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {} + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) + { + UNUSED(a_EntityHit); + UNUSED(a_HitPos); + } /// Called by Chunk when the projectile is eligible for player collection virtual void CollectedBy(cPlayer * a_Dest); diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index df45bb4c2..2571e6b77 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -285,7 +285,7 @@ bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & void cCaveTunnel::Smooth(void) { cCaveDefPoints Pts; - while (true) + for (;;) { if (!RefineDefPoints(m_Points, Pts)) { @@ -331,7 +331,7 @@ void cCaveTunnel::FinishLinear(void) int yd = dy - dx / 2; int zd = dz - dx / 2; - while (true) + for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); @@ -363,7 +363,7 @@ void cCaveTunnel::FinishLinear(void) int xd = dx - dy / 2; int zd = dz - dy / 2; - while (true) + for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); @@ -397,7 +397,7 @@ void cCaveTunnel::FinishLinear(void) int xd = dx - dz / 2; int yd = dy - dz / 2; - while (true) + for (;;) { m_Points.push_back(cCaveDefPoint(PrevX, PrevY, PrevZ, R)); @@ -509,6 +509,7 @@ void cCaveTunnel::ProcessChunk( case E_BLOCK_GRAVEL: case E_BLOCK_SAND: case E_BLOCK_SANDSTONE: + case E_BLOCK_SOULSAND: case E_BLOCK_NETHERRACK: case E_BLOCK_COAL_ORE: case E_BLOCK_IRON_ORE: diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 126a896af..baa5b76b8 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -2,13 +2,11 @@ #include "Globals.h" #include "ChunkGenerator.h" -#include "../World.h" #include "inifile/iniFile.h" -#include "../Root.h" -#include "../Bindings/PluginManager.h" #include "ChunkDesc.h" #include "ComposableGenerator.h" #include "Noise3DGenerator.h" +#include "../MersenneTwister.h" @@ -29,8 +27,9 @@ const unsigned int QUEUE_SKIP_LIMIT = 500; cChunkGenerator::cChunkGenerator(void) : super("cChunkGenerator"), - m_World(NULL), - m_Generator(NULL) + m_Generator(NULL), + m_PluginInterface(NULL), + m_ChunkSink(NULL) { } @@ -47,10 +46,12 @@ cChunkGenerator::~cChunkGenerator() -bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) +bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile) { + m_PluginInterface = &a_PluginInterface; + m_ChunkSink = &a_ChunkSink; + MTRand rnd; - m_World = a_World; m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); @@ -73,7 +74,7 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) return false; } - m_Generator->Initialize(a_World, a_IniFile); + m_Generator->Initialize(a_IniFile); return super::Start(); } @@ -237,14 +238,14 @@ void cChunkGenerator::Execute(void) } // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) + if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request continue; } - if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) + if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; @@ -253,9 +254,6 @@ void cChunkGenerator::Execute(void) LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - // Save the chunk right after generating, so that we don't have to generate it again on next run - m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - NumChunksGenerated++; } // while (!bStop) } @@ -265,27 +263,20 @@ void cChunkGenerator::Execute(void) void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { + ASSERT(m_PluginInterface != NULL); + ASSERT(m_ChunkSink != NULL); + cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ); - cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + m_PluginInterface->CallHookChunkGenerating(ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); - cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + m_PluginInterface->CallHookChunkGenerated(ChunkDesc); #ifdef _DEBUG // Verify that the generator has produced valid data: ChunkDesc.VerifyHeightmap(); #endif - cChunkDef::BlockNibbles BlockMetas; - ChunkDesc.CompressBlockMetas(BlockMetas); - - m_World->SetChunkData( - a_ChunkX, a_ChunkZ, - ChunkDesc.GetBlockTypes(), BlockMetas, - NULL, NULL, // We don't have lighting, chunk will be lighted when needed - &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), - ChunkDesc.GetEntities(), ChunkDesc.GetBlockEntities(), - true - ); + m_ChunkSink->OnChunkGenerated(ChunkDesc); } @@ -304,9 +295,8 @@ cChunkGenerator::cGenerator::cGenerator(cChunkGenerator & a_ChunkGenerator) : -void cChunkGenerator::cGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cChunkGenerator::cGenerator::Initialize(cIniFile & a_IniFile) { - m_World = a_World; UNUSED(a_IniFile); } @@ -319,7 +309,7 @@ EMCSBiome cChunkGenerator::cGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ) cChunkDef::BiomeMap Biomes; int Y = 0; int ChunkX, ChunkZ; - cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ); + cChunkDef::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, ChunkZ); GenerateBiomes(ChunkX, ChunkZ, Biomes); return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ); } diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h index 2d3bb8082..9b2d9eb3c 100644 --- a/src/Generating/ChunkGenerator.h +++ b/src/Generating/ChunkGenerator.h @@ -26,7 +26,6 @@ If the generator queue is overloaded, the generator skips chunks with no clients // fwd: -class cWorld; class cIniFile; class cChunkDesc; @@ -40,7 +39,7 @@ class cChunkGenerator : typedef cIsThread super; public: - /// The interface that a class has to implement to become a generator + /** The interface that a class has to implement to become a generator */ class cGenerator { public: @@ -48,7 +47,7 @@ public: virtual ~cGenerator() {} ; // Force a virtual destructor /// Called to initialize the generator on server startup. - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile); + virtual void Initialize(cIniFile & a_IniFile); /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0; @@ -61,14 +60,59 @@ public: protected: cChunkGenerator & m_ChunkGenerator; - cWorld * m_World; + } ; + + + /** The interface through which the plugins are called for their OnChunkGenerating / OnChunkGenerated hooks. */ + class cPluginInterface + { + public: + // Force a virtual destructor + virtual ~cPluginInterface() {} + + /** Called when the chunk is about to be generated. + The generator may be partly or fully overriden by the implementation + */ + virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) = 0; + + /** Called after the chunk is generated, before it is handed to the chunk sink. + a_ChunkDesc contains the generated chunk data. Implementation may modify this data. + */ + virtual void CallHookChunkGenerated(cChunkDesc & a_ChunkDesc) = 0; + } ; + + + /** The interface through which the generated chunks are handed to the cWorld or whoever created us. */ + class cChunkSink + { + public: + // Force a virtual destructor + virtual ~cChunkSink() {} + + /** Called after the chunk has been generated + The interface may store the chunk, send it over network, whatever. + The chunk is not expected to be modified, but the generator will survive if the implementation + changes the data within. All changes are ignored, though. + */ + virtual void OnChunkGenerated(cChunkDesc & a_ChunkDesc) = 0; + + /** Called just before the chunk generation is started, + to verify that it hasn't been generated in the meantime. + If this callback returns true, the chunk is not generated. + */ + virtual bool IsChunkValid(int a_ChunkX, int a_ChunkZ) = 0; + + /** Called when the generator is overloaded to skip chunks that are no longer needed. + If this callback returns false, the chunk is not generated. + */ + virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0; } ; cChunkGenerator (void); ~cChunkGenerator(); - bool Start(cWorld * a_World, cIniFile & a_IniFile); + bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile); void Stop(void); /// Queues the chunk for generation; removes duplicate requests @@ -91,8 +135,6 @@ public: private: - cWorld * m_World; - int m_Seed; cCriticalSection m_CS; @@ -101,6 +143,13 @@ private: cEvent m_evtRemoved; ///< Set when an item is removed from the queue cGenerator * m_Generator; ///< The actual generator engine used to generate chunks + + /** The plugin interface that may modify the generated chunks */ + cPluginInterface * m_PluginInterface; + + /** The destination where the generated chunks are sent */ + cChunkSink * m_ChunkSink; + // cIsThread override: virtual void Execute(void) override; diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp index f929ddc2f..60356fe46 100644 --- a/src/Generating/CompoGen.cpp +++ b/src/Generating/CompoGen.cpp @@ -589,7 +589,22 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc) for (int y = 0; y < SEGMENT_HEIGHT; y++) { int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT; - a_ChunkDesc.SetBlockType(x, y + Segment, z, (Val < m_Threshold) ? E_BLOCK_NETHERRACK : E_BLOCK_AIR); + BLOCKTYPE Block = E_BLOCK_AIR; + if (Val < m_Threshold) // Don't calculate if the block should be Netherrack or Soulsand when it's already decided that it's air. + { + NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(BaseX + x)) / 8; + NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(BaseZ + z)) / 8; + NOISE_DATATYPE CompBlock = m_Noise1.CubicNoise3D(NoiseX, (float) (y + Segment) / 2, NoiseY); + if (CompBlock < -0.5) + { + Block = E_BLOCK_SOULSAND; + } + else + { + Block = E_BLOCK_NETHERRACK; + } + } + a_ChunkDesc.SetBlockType(x, y + Segment, z, Block); } } diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index c86568c95..87c4d2c52 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -28,11 +28,88 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cTerrainCompositionGen: +cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed) +{ + AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); + if (CompoGenName.empty()) + { + LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\"."); + CompoGenName = "Biomal"; + a_IniFile.SetValue("Generator", "CompositionGen", CompoGenName); + } + + cTerrainCompositionGen * res = NULL; + if (NoCaseCompare(CompoGenName, "sameblock") == 0) + { + res = new cCompoGenSameBlock; + } + else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0) + { + res = new cCompoGenDebugBiomes; + } + else if (NoCaseCompare(CompoGenName, "classic") == 0) + { + res = new cCompoGenClassic; + } + else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0) + { + res = new cDistortedHeightmap(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(CompoGenName, "end") == 0) + { + res = new cEndGen(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "nether") == 0) + { + res = new cCompoGenNether(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) + { + res = new cNoise3DComposable(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "biomal") == 0) + { + res = new cCompoGenBiomal(a_Seed); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cCompoGenBiomal..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 500; x++) + { + cChunkDesc Desc(200 + x * 8, 200 + x * 8); + a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap()); + a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap()); + res->ComposeTerrain(Desc); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + else + { + LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str()); + a_IniFile.DeleteValue("Generator", "CompositionGen"); + a_IniFile.SetValue("Generator", "CompositionGen", "Biomal"); + return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed); + } + ASSERT(res != NULL); + + // Read the settings from the ini file: + res->InitializeCompoGen(a_IniFile); + + return res; +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cComposableGenerator: + cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) : super(a_ChunkGenerator), m_BiomeGen(NULL), @@ -80,9 +157,9 @@ cComposableGenerator::~cComposableGenerator() -void cComposableGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cComposableGenerator::Initialize(cIniFile & a_IniFile) { - super::Initialize(a_World, a_IniFile); + super::Initialize(a_IniFile); InitBiomeGen(a_IniFile); InitHeightGen(a_IniFile); @@ -173,60 +250,8 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) { - AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); - if (HeightGenName.empty()) - { - LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); - HeightGenName = "Biomal"; - } - - int Seed = m_ChunkGenerator.GetSeed(); bool CacheOffByDefault = false; - if (NoCaseCompare(HeightGenName, "flat") == 0) - { - m_HeightGen = new cHeiGenFlat; - CacheOffByDefault = true; // We're generating faster than a cache would retrieve data - } - else if (NoCaseCompare(HeightGenName, "classic") == 0) - { - m_HeightGen = new cHeiGenClassic(Seed); - } - else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) - { - m_HeightGen = new cDistortedHeightmap(Seed, *m_BiomeGen); - } - else if (NoCaseCompare(HeightGenName, "End") == 0) - { - m_HeightGen = new cEndGen(Seed); - } - else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) - { - m_HeightGen = new cNoise3DComposable(Seed); - } - else // "biomal" or <not found> - { - if (NoCaseCompare(HeightGenName, "biomal") != 0) - { - LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str()); - } - m_HeightGen = new cHeiGenBiomal(Seed, *m_BiomeGen); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cHeiGenBiomal..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 500; x++) - { - cChunkDef::HeightMap Heights; - m_HeightGen->GenHeightMap(x * 5, x * 5, Heights); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - - // Read the settings: - m_HeightGen->InitializeHeightGen(a_IniFile); + m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, *m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault); // Add a cache, if requested: int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64); @@ -251,67 +276,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile) { - int Seed = m_ChunkGenerator.GetSeed(); - AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); - if (CompoGenName.empty()) - { - LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\"."); - CompoGenName = "Biomal"; - } - if (NoCaseCompare(CompoGenName, "sameblock") == 0) - { - m_CompositionGen = new cCompoGenSameBlock; - } - else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0) - { - m_CompositionGen = new cCompoGenDebugBiomes; - } - else if (NoCaseCompare(CompoGenName, "classic") == 0) - { - m_CompositionGen = new cCompoGenClassic; - } - else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0) - { - m_CompositionGen = new cDistortedHeightmap(Seed, *m_BiomeGen); - } - else if (NoCaseCompare(CompoGenName, "end") == 0) - { - m_CompositionGen = new cEndGen(Seed); - } - else if (NoCaseCompare(CompoGenName, "nether") == 0) - { - m_CompositionGen = new cCompoGenNether(Seed); - } - else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) - { - m_CompositionGen = new cNoise3DComposable(m_ChunkGenerator.GetSeed()); - } - else - { - if (NoCaseCompare(CompoGenName, "biomal") != 0) - { - LOGWARN("Unknown CompositionGen \"%s\", using \"biomal\" instead.", CompoGenName.c_str()); - } - m_CompositionGen = new cCompoGenBiomal(Seed); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cCompoGenBiomal..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 500; x++) - { - cChunkDesc Desc(200 + x * 8, 200 + x * 8); - m_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap()); - m_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap()); - m_CompositionGen->ComposeTerrain(Desc); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - - // Read the settings from the ini file: - m_CompositionGen->InitializeCompoGen(a_IniFile); + m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, *m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed()); int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64); if (CompoGenCacheSize > 1) @@ -404,13 +369,14 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int Seed = m_ChunkGenerator.GetSeed(); AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); + eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); AStringVector Str = StringSplitAndTrim(Structures, ","); for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) { // Finishers, alpha-sorted: if (NoCaseCompare(*itr, "BottomLava") == 0) { - int DefaultBottomLavaLevel = (m_World->GetDimension() == dimNether) ? 30 : 10; + int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10; int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel); m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel)); } @@ -424,7 +390,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "LavaSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, *m_World)); + m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)); } else if (NoCaseCompare(*itr, "Lilypads") == 0) { @@ -444,7 +410,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "WaterSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, *m_World)); + m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)); } } // for itr - Str[] } diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h index 732f64303..29add0636 100644 --- a/src/Generating/ComposableGenerator.h +++ b/src/Generating/ComposableGenerator.h @@ -50,7 +50,7 @@ public: virtual void InitializeBiomeGen(cIniFile & a_IniFile) {} /// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided. - /// a_CacheOffByDefault gets set to whether the cache should be enabled by default + /// a_CacheOffByDefault gets set to whether the cache should be disabled by default /// Used in BiomeVisualiser, too. /// Implemented in BioGen.cpp! static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault); @@ -77,6 +77,13 @@ public: /// Reads parameters from the ini file, prepares generator for use. virtual void InitializeHeightGen(cIniFile & a_IniFile) {} + + /** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided. + a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes + a_CacheOffByDefault gets set to whether the cache should be disabled by default + Implemented in HeiGen.cpp! + */ + static cTerrainHeightGen * CreateHeightGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault); } ; @@ -97,6 +104,12 @@ public: /// Reads parameters from the ini file, prepares generator for use. virtual void InitializeCompoGen(cIniFile & a_IniFile) {} + + /** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided. + a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes + a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values + */ + static cTerrainCompositionGen * CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed); } ; @@ -149,7 +162,7 @@ public: cComposableGenerator(cChunkGenerator & a_ChunkGenerator); virtual ~cComposableGenerator(); - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override; + virtual void Initialize(cIniFile & a_IniFile) override; virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override; diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index 15e352e30..eb9fe92ba 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -774,10 +774,11 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in return; } default: + { ASSERT(!"Unhandled biome"); return; + } } // switch (Biome) - ASSERT(!"Unexpected fallthrough"); } diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 866551e8a..4915e6818 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -520,7 +520,7 @@ void cFinishGenPreSimulator::StationarizeFluid( /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cFinishGenFluidSprings: -cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World) : +cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension) : m_Noise(a_Seed + a_Fluid * 100), // Need to take fluid into account, otherwise water and lava springs generate next to each other m_HeightDistribution(255), m_Fluid(a_Fluid) @@ -528,8 +528,8 @@ cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cI bool IsWater = (a_Fluid == E_BLOCK_WATER); AString SectionName = IsWater ? "WaterSprings" : "LavaSprings"; AString DefaultHeightDistribution; - int DefaultChance; - switch (a_World.GetDimension()) + int DefaultChance = 0; + switch (a_Dimension) { case dimNether: { diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index ed7df5909..d89ffed15 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -164,7 +164,7 @@ class cFinishGenFluidSprings : public cFinishGen { public: - cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World); + cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension); protected: diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 2bf641089..10710b4a1 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -7,6 +7,9 @@ #include "HeiGen.h" #include "../LinearUpscale.h" #include "inifile/iniFile.h" +#include "DistortedHeightmap.h" +#include "EndGen.h" +#include "Noise3DGenerator.h" @@ -14,6 +17,77 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cTerrainHeightGen: + +cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault) +{ + AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); + if (HeightGenName.empty()) + { + LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); + HeightGenName = "Biomal"; + } + + a_CacheOffByDefault = false; + cTerrainHeightGen * res = NULL; + if (NoCaseCompare(HeightGenName, "flat") == 0) + { + res = new cHeiGenFlat; + a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data + } + else if (NoCaseCompare(HeightGenName, "classic") == 0) + { + res = new cHeiGenClassic(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) + { + res = new cDistortedHeightmap(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(HeightGenName, "End") == 0) + { + res = new cEndGen(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) + { + res = new cNoise3DComposable(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "biomal") == 0) + { + res = new cHeiGenBiomal(a_Seed, a_BiomeGen); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cHeiGenBiomal..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 500; x++) + { + cChunkDef::HeightMap Heights; + res->GenHeightMap(x * 5, x * 5, Heights); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + else + { + // No match found, force-set the default and retry + LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str()); + a_IniFile.DeleteValue("Generator", "HeightGen"); + a_IniFile.SetValue("Generator", "HeightGen", "Biomal"); + return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault); + } + + // Read the settings: + res->InitializeHeightGen(a_IniFile); + + return res; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cHeiGenFlat: void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index 2511bb656..afa40c647 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -150,10 +150,8 @@ cNoise3DGenerator::~cNoise3DGenerator() -void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cNoise3DGenerator::Initialize(cIniFile & a_IniFile) { - m_World = a_World; - // Params: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62); m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0); diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h index 0d211cddc..42f61a854 100644 --- a/src/Generating/Noise3DGenerator.h +++ b/src/Generating/Noise3DGenerator.h @@ -24,7 +24,7 @@ public: cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator); virtual ~cNoise3DGenerator(); - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override; + virtual void Initialize(cIniFile & a_IniFile) override; virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override; diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp index 6413b963b..cfda47e32 100644 --- a/src/Generating/Ravines.cpp +++ b/src/Generating/Ravines.cpp @@ -381,7 +381,7 @@ void cStructGenRavines::cRavine::FinishLinear(void) int R = itr->m_Radius; int T = itr->m_Top; int B = itr->m_Bottom; - while (true) + for (;;) { m_Points.push_back(cRavDefPoint(PrevX, PrevZ, R, T, B)); if ((PrevX == x1) && (PrevZ == z1)) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index fbed57cb6..7e8a3c75f 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -216,7 +216,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); break; } - + + case biBirchForestM: + case biBirchForestHillsM: + { + GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + break; + } + case biRoofedForest: case biColdTaiga: case biColdTaigaHills: @@ -237,8 +244,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biIcePlainsSpikes: case biJungleM: case biJungleEdgeM: - case biBirchForestM: - case biBirchForestHillsM: case biRoofedForestM: case biColdTaigaM: case biMegaSpruceTaiga: @@ -377,6 +382,44 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois +void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) +{ + int Height = 9 + (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) % 3); + + // Prealloc, so that we don't realloc too often later: + a_LogBlocks.reserve(Height); + a_OtherBlocks.reserve(80); + + // The entire trunk, out of logs: + for (int i = Height - 1; i >= 0; --i) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_BIRCH)); + } + int h = a_BlockY + Height; + + // Top layer - just the Plus: + PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + a_OtherBlocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH)); // There's no log at this layer + h--; + + // Second layer - log, Plus and maybe Corners: + PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 1, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + h--; + + // Third and fourth layers - BigO2 and maybe 2*Corners: + for (int Row = 0; Row < 2; Row++) + { + PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x3fffffff + Row * 0x10000000, a_OtherBlocks, 2, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + h--; + } // for Row - 2* +} + + + + + void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { // Half chance for a spruce, half for a pine: diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index f5148ad6f..514158eb7 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -63,6 +63,9 @@ void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a /// Generates an image of a random birch tree void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); +/// Generates an image of a random large birch tree +void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks,sSetBlockVector & a_OtherBlocks); + /// Generates an image of a random conifer tree void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); diff --git a/src/Globals.h b/src/Globals.h index 58badf4dd..d2080b8eb 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -14,7 +14,24 @@ #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 : 4127) // Conditional expression is constant + #pragma warning(3 : 4189) // Local variable is initialized but not referenced + #pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch + #pragma warning(3 : 4310) // Cast truncates constant value + #pragma warning(3 : 4389) // Signed/unsigned mismatch + #pragma warning(3 : 4505) // Unreferenced local function has been removed + #pragma warning(3 : 4701) // Potentially unitialized local variable used + #pragma warning(3 : 4702) // Unreachable code + #pragma warning(3 : 4706) // Assignment within conditional expression + + // Disabling this warning, because we know what we're doing when we're doing this: + #pragma warning(disable: 4355) // 'this' used in initializer list + + // 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 +209,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 @@ -216,6 +233,7 @@ public: // Common headers (part 2, with macros): #include "ChunkDef.h" +#include "BiomeDef.h" #include "BlockID.h" #include "Entities/Effects.h" 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/MultipartParser.cpp b/src/HTTPServer/MultipartParser.cpp index b49f6ec07..14c2c00fa 100644 --- a/src/HTTPServer/MultipartParser.cpp +++ b/src/HTTPServer/MultipartParser.cpp @@ -156,7 +156,7 @@ void cMultipartParser::Parse(const char * a_Data, int a_Size) // Append to buffer, then parse it: m_IncomingData.append(a_Data, a_Size); - while (true) + for (;;) { if (m_EnvelopeParser.IsInHeaders()) { 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/Inventory.cpp b/src/Inventory.cpp index a9b4ab9c5..a7f77cf6d 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -57,6 +57,8 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlo int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots) { + + UNUSED(a_ConsiderEmptySlots); if ((a_BeginSlotNum < 0) || (a_BeginSlotNum >= invNumSlots)) { LOGWARNING("%s: Bad BeginSlotNum, got %d, there are %d slots; correcting to 0.", __FUNCTION__, a_BeginSlotNum, invNumSlots - 1); @@ -96,8 +98,6 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int - - int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst) { cItem ToAdd(a_Item); 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/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 941ce3b71..b2eaee63a 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -9,9 +9,11 @@ #pragma once +#include "../Bindings/PluginManager.h" #include "../Entities/Floater.h" #include "../Entities/Entity.h" #include "../Item.h" +#include "../Root.h" @@ -210,10 +212,14 @@ public: } } - + if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops)) + { + return true; + } Vector3d FloaterPos = FloaterInfo.GetPos(); Vector3d FlyDirection = a_Player->GetEyePosition() - FloaterPos; a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.y + 1, FlyDirection.z); + cRoot::Get()->GetPluginManager()->CallHookPlayerFished(*a_Player, Drops); } } else diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index e39bb054b..db0ffc9db 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -25,7 +25,13 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); /// Called when the client sends the SHOOT status in the lclk packet - virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {} + virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) + { + UNUSED(a_BlockX); + UNUSED(a_BlockY); + UNUSED(a_BlockZ); + UNUSED(a_BlockFace); + } /// Called while the player diggs a block using this item virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 8ca86663f..67f0d38bd 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -56,7 +56,6 @@ public: case E_ITEM_SEEDS: a_BlockType = E_BLOCK_CROPS; return true; default: a_BlockType = E_BLOCK_AIR; return true; } - return false; } } ; diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index d7e60e458..a823c08cc 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -189,7 +189,7 @@ void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ) { if ( (itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) && - (itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) + (itr->z - a_ChunkZ >= -1) && (itr->z - a_ChunkZ <= 1) ) { // It is a neighbor @@ -216,7 +216,7 @@ void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ) void cLightingThread::Execute(void) { - while (true) + for (;;) { { cCSLock Lock(m_CS); @@ -495,6 +495,7 @@ void cLightingThread::CalcLightStep( int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut ) { + UNUSED(a_IsSeedIn); int NumSeedsOut = 0; for (int i = 0; i < a_NumSeedsIn; i++) { diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp index 9fcbca915..da1c7f2fd 100644 --- a/src/LineBlockTracer.cpp +++ b/src/LineBlockTracer.cpp @@ -196,8 +196,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld() // This is the actual line tracing loop. - bool Finished = false; - while (true) + for (;;) { // Report the current block through the callbacks: if (a_Chunk == NULL) 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 new file mode 100644 index 000000000..6c3d58295 --- /dev/null +++ b/src/OSSupport/Queue.h @@ -0,0 +1,178 @@ + +// Queue.h + +// Implements the cQueue class representing a thread safe queue + +#pragma once + +/* +Items can be added multiple times to a queue, there are two functions for +adding, EnqueueItem() and EnqueueItemIfNotPresent(). The first one always +enqueues the specified item, the second one checks if the item is already +present and only queues it if it isn't. + +Usage: +To create a queue of type T, instantiate a cQueue<T> object. You can also +modify the behavior of the queue when deleting items and when adding items +that are already in the queue by providing a second parameter, a class that +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 +template<class T> +struct cQueueFuncs +{ +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> > +class cQueue +{ + // 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) + { + cCSLock Lock(m_CS); + m_Contents.push_back(a_Item); + m_evtAdded.Set(); + } + + + /// 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) + { + if ((*itr) == a_Item) + { + Funcs::Combine(*itr, a_Item); + return; + } + } + 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) + { + cCSLock Lock(m_CS); + if (m_Contents.size() == 0) + { + return false; + } + 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(void) + { + cCSLock Lock(m_CS); + while (m_Contents.size() == 0) + { + cCSUnlock Unlock(Lock); + m_evtAdded.Wait(); + } + ItemType item = m_Contents.front(); + m_Contents.pop_front(); + m_evtRemoved.Set(); + return item; + } + + + /// 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. + void Clear(void) + { + cCSLock Lock(m_CS); + while (!m_Contents.empty()) + { + Funcs::Delete(m_Contents.front()); + m_Contents.pop_front(); + } + } + + + /// 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(); + } + + + /// 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) + { + if ((*itr) == a_Item) + { + m_Contents.erase(itr); + m_evtRemoved.Set(); + return true; + } + } + return false; + } + +private: + /// 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/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index ecbac3aeb..858729c49 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -61,6 +61,9 @@ public: class cCallback { public: + // Force a virtual destructor in all subclasses: + virtual ~cCallback() {} + /// Called when data is received from the remote party virtual void DataReceived(const char * a_Data, int a_Size) = 0; diff --git a/src/Piston.cpp b/src/Piston.cpp index b15e7d95e..75eeb5e98 100644 --- a/src/Piston.cpp +++ b/src/Piston.cpp @@ -238,6 +238,7 @@ bool cPiston::CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) bool cPiston::CanBreakPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { + UNUSED(a_BlockMeta); return g_BlockPistonBreakable[a_BlockType]; } diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index fdbffb3e9..3293da32c 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -87,6 +87,7 @@ public: virtual void SendPlayerMoveLook (void) = 0; virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; virtual void SendRespawn (void) = 0; virtual void SendExperience (void) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index e49dd43ff..48c085ae5 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -704,6 +704,20 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_PLUGIN_MESSAGE); + WriteString(a_Channel); + WriteShort((short)a_Message.size()); + SendData(a_Message.data(), a_Message.size()); + Flush(); +} + + + + + void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cCSLock Lock(m_CSPacket); diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 0b32137d8..d0e5c9428 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -63,6 +63,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 346607b79..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()); @@ -886,15 +897,15 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A time_t CurTime = time(NULL); CryptoPP::RandomPool rng; rng.Put((const byte *)&CurTime, sizeof(CurTime)); - byte DecryptedNonce[MAX_ENC_LEN]; - DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce); + Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; + DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), (byte *)DecryptedNonce); if (!res.isValidCoding || (res.messageLength != 4)) { LOGD("Bad nonce length"); m_Client->Kick("Hacked client"); return; } - if (ntohl(*((int *)DecryptedNonce)) != (unsigned)(uintptr_t)this) + if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this) { LOGD("Bad nonce value"); m_Client->Kick("Hacked client"); @@ -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..80fc8740a 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:4189) + #pragma warning(disable:4231) + #pragma warning(disable:4244) + #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..9c46c6843 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -628,6 +628,18 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + cPacketizer Pkt(*this, 0x3f); + Pkt.WriteString(a_Channel); + Pkt.WriteShort((short)a_Message.size()); + Pkt.WriteBuf(a_Message.data(), a_Message.size()); +} + + + + + void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cPacketizer Pkt(*this, 0x1E); @@ -983,10 +995,9 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) } // Handle all complete packets: - while (true) + for (;;) { UInt32 PacketLen; - int PacketStart = m_ReceivedData.GetDataStart(); if (!m_ReceivedData.ReadVarInt(PacketLen)) { // Not enough data @@ -1113,9 +1124,12 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) cRoot::Get()->GetServer()->GetMaxPlayers(), cRoot::Get()->GetServer()->GetNumPlayers() ); - AppendPrintf(Response, "\"description\":{\"text\":\"%s\"}", + AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", cRoot::Get()->GetServer()->GetDescription().c_str() ); + AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"", + cRoot::Get()->GetServer()->GetFaviconData().c_str() + ); Response.append("}"); cPacketizer Pkt(*this, 0x00); // Response packet @@ -1374,7 +1388,7 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length); AString Data; a_ByteBuffer.ReadString(Data, Length); - // TODO: m_Client->HandlePluginMessage(Channel, Data); + m_Client->HandlePluginMessage(Channel, Data); } diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index cc0eda1e7..fd6b1fc0f 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 + @@ -72,6 +86,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 1cae4a750..a21f4f042 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); } } @@ -476,6 +476,16 @@ void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPluginMessage(a_Channel, a_Message); +} + + + + + void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index fbcf59f3b..e94f4cde8 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -98,6 +98,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; diff --git a/src/Root.cpp b/src/Root.cpp index 798f965be..fa1fdb37a 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -596,10 +596,10 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac public: cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) : - m_Callback(a_Callback), m_BestRating(0), m_NameLength(a_PlayerName.length()), m_PlayerName(a_PlayerName), + m_Callback(a_Callback), m_BestMatch(NULL), m_NumMatches(0) {} @@ -701,9 +701,9 @@ int cRoot::GetPhysicalRAMUsage(void) { AString Line; std::getline(StatFile, Line); - if (strncmp(Line.c_str(), "VmRSS:", 7) == 0) + if (strncmp(Line.c_str(), "VmRSS:", 6) == 0) { - int res = atoi(Line.c_str() + 8); + int res = atoi(Line.c_str() + 7); return (res == 0) ? -1 : res; // If parsing failed, return -1 } } diff --git a/src/Server.cpp b/src/Server.cpp index a93be9a5b..49067c17f 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -173,6 +173,7 @@ void cServer::ClientMovedToWorld(const cClientHandle * a_Client) void cServer::PlayerCreated(const cPlayer * a_Player) { + UNUSED(a_Player); // To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread cCSLock Lock(m_CSPlayerCountDiff); m_PlayerCountDiff += 1; @@ -184,6 +185,7 @@ void cServer::PlayerCreated(const cPlayer * a_Player) void cServer::PlayerDestroying(const cPlayer * a_Player) { + UNUSED(a_Player); // To avoid deadlocks, the player count is not handled directly, but rather posted onto the tick thread cCSLock Lock(m_CSPlayerCountDiff); m_PlayerCountDiff -= 1; @@ -201,6 +203,8 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) m_PlayerCount = 0; m_PlayerCountDiff = 0; + m_FaviconData = Base64Encode(cFile::ReadWholeFile("favicon.png")); // Will return empty string if file nonexistant; client doesn't mind + if (m_bIsConnected) { LOGERROR("ERROR: Trying to initialize server while server is already running!"); @@ -491,7 +495,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac if (split[0].compare("killmem") == 0) { - while (true) + for (;;) { new char[100 * 1024 * 1024]; // Allocate and leak 100 MiB in a loop -> fill memory and kill MCS } @@ -514,6 +518,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output) { + UNUSED(a_Split); typedef std::pair<AString, AString> AStringPair; typedef std::vector<AStringPair> AStringPairs; @@ -525,6 +530,8 @@ void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { + UNUSED(a_Plugin); + UNUSED(a_Permission); if (!a_HelpString.empty()) { m_Commands.push_back(AStringPair(a_Command, a_HelpString)); diff --git a/src/Server.h b/src/Server.h index 0d93469a5..d79417fb0 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 @@ -35,6 +50,8 @@ class cServer // tolua_export : public cListenThread::cCallback { // tolua_export public: // tolua_export + + virtual ~cServer() {} bool InitServer(cIniFile & a_SettingsIni); // tolua_begin @@ -89,6 +106,9 @@ public: // tolua_export /// Notifies the server that a player is being destroyed; the server uses this to adjust the number of players void PlayerDestroying(const cPlayer * a_Player); + + /* Returns base64 encoded favicon data (obtained from favicon.png) */ + const AString & GetFaviconData(void) const { return m_FaviconData; } CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; } CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; } @@ -166,6 +186,7 @@ private: cRCONServer m_RCONServer; AString m_Description; + AString m_FaviconData; int m_MaxPlayers; bool m_bIsHardcore; diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h index 66c31b440..9ccc3ef4f 100644 --- a/src/Simulator/FireSimulator.h +++ b/src/Simulator/FireSimulator.h @@ -22,7 +22,7 @@ public: cFireSimulator(cWorld & a_World, cIniFile & a_IniFile); ~cFireSimulator(); - virtual void Simulate(float a_Dt) override {} // not used + virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override; diff --git a/src/Simulator/NoopFluidSimulator.h b/src/Simulator/NoopFluidSimulator.h index 8f894433f..9113aec3c 100644 --- a/src/Simulator/NoopFluidSimulator.h +++ b/src/Simulator/NoopFluidSimulator.h @@ -27,8 +27,14 @@ public: } // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override {} - virtual void Simulate(float a_Dt) override {} + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + { + UNUSED(a_BlockX); + UNUSED(a_BlockY); + UNUSED(a_BlockZ); + UNUSED(a_Chunk); + } + virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} } ; diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 60c86a3c5..1080c3f81 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -19,7 +19,7 @@ public: cRedstoneSimulator(cWorld & a_World); ~cRedstoneSimulator(); - virtual void Simulate(float a_Dt) override {}; // Not used in this simulator + virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); } @@ -271,4 +271,4 @@ private: default: return false; } } -};
\ No newline at end of file +}; diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h index 6e9ea15ac..6e64aa425 100644 --- a/src/Simulator/SandSimulator.h +++ b/src/Simulator/SandSimulator.h @@ -15,7 +15,7 @@ public: cSandSimulator(cWorld & a_World, cIniFile & a_IniFile); // cSimulator overrides: - virtual void Simulate(float a_Dt) override {} // Unused in this simulator + virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override; diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index 5cd0e8657..a25b7f1b6 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -25,7 +25,14 @@ public: virtual void Simulate(float a_Dt) = 0; /// Called in each tick for each chunk, a_Dt is the time passed since the last tick, in msec; direct access to chunk data available - virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) {}; + virtual void SimulateChunk(float a_Dt, int a_ChunkX, + int a_ChunkZ, cChunk * a_Chunk) + { + UNUSED(a_Dt); + UNUSED(a_ChunkX); + UNUSED(a_ChunkZ); + UNUSED(a_Chunk); + }; /// Called when a block changes virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index 36946b282..e15058840 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -74,7 +74,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed return res; } - while (true) + for (;;) { res = deflate(&strm, Z_FINISH); switch (res) @@ -137,7 +137,7 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U return res; } - while (true) + for (;;) { res = inflate(&strm, Z_FINISH); switch (res) diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index f7aeeed26..0b38297ef 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -47,15 +47,13 @@ AString & AppendVPrintf(AString & str, const char *format, va_list args) #endif // _MSC_VER // Allocate a buffer and printf into it: - str.resize(len + 1); - // HACK: we're accessing AString's internal buffer in a way that is NOT guaranteed to always work. But it works on all STL implementations tested. - // I can't think of any other way that is safe, doesn't allocate twice as much space as needed and doesn't use C++11 features like the move constructor + std::vector<char> Buffer(len + 1); #ifdef _MSC_VER - vsprintf_s((char *)str.data(), len + 1, format, args); + vsprintf_s((char *)&(Buffer.front()), Buffer.size(), format, args); #else // _MSC_VER - vsnprintf((char *)str.data(), len + 1, format, args); + vsnprintf((char *)&(Buffer.front()), Buffer.size(), format, args); #endif // else _MSC_VER - str.resize(len); + str.append(&(Buffer.front()), Buffer.size() - 1); return str; } @@ -612,7 +610,7 @@ AString StripColorCodes(const AString & a_Message) { AString res(a_Message); size_t idx = 0; - while (true) + for (;;) { idx = res.find("\xc2\xa7", idx); if (idx == AString::npos) @@ -759,7 +757,86 @@ AString Base64Decode(const AString & a_Base64String) } } res.resize(o >> 3); - return res;} + return res; +} + + + + + +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','+','/' + }; + + AString 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]; +} + + + + + +int GetBEInt(const char * a_Mem) +{ + return (((int)a_Mem[0]) << 24) | (((int)a_Mem[1]) << 16) | (((int)a_Mem[2]) << 8) | a_Mem[3]; +} + + + + + +void SetBEInt(char * a_Mem, Int32 a_Value) +{ + a_Mem[0] = a_Value >> 24; + a_Mem[1] = (a_Value >> 16) & 0xff; + a_Mem[2] = (a_Value >> 8) & 0xff; + a_Mem[3] = a_Value & 0xff; +} diff --git a/src/StringUtils.h b/src/StringUtils.h index 3917cc4ec..2373f3843 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -81,6 +81,18 @@ 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); + +/// Reads four bytes from the specified memory location and interprets them as BigEndian int +extern int GetBEInt(const char * a_Mem); + +/// Writes four bytes to the specified memory location so that they interpret as BigEndian int +extern void SetBEInt(char * a_Mem, Int32 a_Value); + // If you have any other string helper functions, declare them here diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 61e432665..a721e6b7e 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -491,7 +491,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) return; } cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; - do + for (;;) { // Try distributing the result. If it fails, bail out: cItem ResultCopy(Result); @@ -517,7 +517,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) // The recipe has changed, bail out return; } - } while (true); + } } diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index a1f0842aa..e6a5a01b3 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -305,6 +305,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque void cWebAdmin::HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { + UNUSED(a_Request); static const char LoginForm[] = \ "<h1>MCServer WebAdmin</h1>" \ "<center>" \ @@ -450,6 +451,7 @@ AString cWebAdmin::GetBaseURL(const AStringVector & a_URLSplit) void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { + UNUSED(a_Connection); const AString & URL = a_Request.GetURL(); if ( (strncmp(URL.c_str(), "/webadmin", 9) == 0) || @@ -473,6 +475,7 @@ void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_ void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) { + UNUSED(a_Connection); cRequestData * Data = (cRequestData *)(a_Request.GetUserData()); if (Data == NULL) { diff --git a/src/WebAdmin.h b/src/WebAdmin.h index 0907e7bc3..3eb807640 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -105,7 +105,7 @@ public: cWebAdmin(void); - ~cWebAdmin(); + virtual ~cWebAdmin(); /// Initializes the object. Returns true if successfully initialized and ready to start bool Init(void); @@ -169,9 +169,16 @@ protected: virtual void OnBody(const char * a_Data, int a_Size) override; // cHTTPFormParser::cCallbacks overrides. Files are ignored: - virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) override {} - virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override {} - virtual void OnFileEnd(cHTTPFormParser & a_Parser) override {} + virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override + { + UNUSED(a_FileName); + } + virtual void OnFileData(cHTTPFormParser &, const char * a_Data, int a_Size) override + { + UNUSED(a_Data); + UNUSED(a_Size); + } + virtual void OnFileEnd(cHTTPFormParser &) override {} } ; diff --git a/src/World.cpp b/src/World.cpp index 28c46c27e..1cf82d641 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -10,6 +10,7 @@ #include "Root.h" #include "inifile/iniFile.h" #include "ChunkMap.h" +#include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" // Entities (except mobs): @@ -238,6 +239,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_SkyDarkness(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) + m_GeneratorCallbacks(*this), m_TickThread(*this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -367,10 +369,13 @@ void cWorld::InitializeSpawn(void) cWorldLoadProgress Progress(this); // Wait for the loader to finish loading - m_Storage.WaitForQueuesEmpty(); + m_Storage.WaitForLoadQueueEmpty(); // Wait for the generator to finish generating m_Generator.WaitForQueueEmpty(); + + // Wait for the loader to finish saving + m_Storage.WaitForSaveQueueEmpty(); Progress.Stop(); } @@ -580,7 +585,7 @@ void cWorld::Start(void) m_Lighting.Start(this); m_Storage.Start(this, m_StorageSchema); - m_Generator.Start(this, IniFile); + m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); m_ChunkSender.Start(this); m_TickThread.Start(); @@ -723,6 +728,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec) void cWorld::TickWeather(float a_Dt) { + UNUSED(a_Dt); // There are no weather changes anywhere but in the Overworld: if (GetDimension() != dimOverworld) { @@ -794,7 +800,7 @@ void cWorld::TickMobs(float a_Dt) cMonster::mfAmbient, cMonster::mfWater, } ; - for (int i = 0; i < ARRAYCOUNT(AllFamilies); i++) + for (size_t i = 0; i < ARRAYCOUNT(AllFamilies); i++) { cMonster::eFamily Family = AllFamilies[i]; int SpawnDelay = cMonster::GetSpawnDelay(Family); @@ -1643,6 +1649,7 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff) { + UNUSED(a_InitialVelocityCoeff); cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec); TNT->Initialize(this); // TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff @@ -2838,3 +2845,77 @@ void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld::cChunkGeneratorCallbacks: + +cWorld::cChunkGeneratorCallbacks::cChunkGeneratorCallbacks(cWorld & a_World) : + m_World(&a_World) +{ +} + + + + + +void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc) +{ + cChunkDef::BlockNibbles BlockMetas; + a_ChunkDesc.CompressBlockMetas(BlockMetas); + + m_World->SetChunkData( + a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), + a_ChunkDesc.GetBlockTypes(), BlockMetas, + NULL, NULL, // We don't have lighting, chunk will be lighted when needed + &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), + a_ChunkDesc.GetEntities(), a_ChunkDesc.GetBlockEntities(), + true + ); + + // Save the chunk right after generating, so that we don't have to generate it again on next run + m_World->GetStorage().QueueSaveChunk(a_ChunkDesc.GetChunkX(), 0, a_ChunkDesc.GetChunkZ()); +} + + + + + +bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(int a_ChunkX, int a_ChunkZ) +{ + return m_World->IsChunkValid(a_ChunkX, a_ChunkZ); +} + + + + + +bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) +{ + return m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ); +} + + + + + +void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) +{ + cPluginManager::Get()->CallHookChunkGenerating( + m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + ); +} + + + + + +void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) +{ + cPluginManager::Get()->CallHookChunkGenerated( + m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + ); +} + + + + + diff --git a/src/World.h b/src/World.h index c067252d9..b61708d03 100644 --- a/src/World.h +++ b/src/World.h @@ -78,6 +78,7 @@ public: class cTask { public: + virtual ~cTask(){}; virtual void Run(cWorld & a_World) = 0; } ; @@ -145,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 @@ -635,6 +636,27 @@ private: virtual void Execute(void) override; } ; + + /** Implementation of the callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */ + class cChunkGeneratorCallbacks : + public cChunkGenerator::cChunkSink, + public cChunkGenerator::cPluginInterface + { + cWorld * m_World; + + // cChunkSink overrides: + virtual void OnChunkGenerated (cChunkDesc & a_ChunkDesc) override; + virtual bool IsChunkValid (int a_ChunkX, int a_ChunkZ) override; + virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) override; + + // cPluginInterface overrides: + virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) override; + virtual void CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) override; + + public: + cChunkGeneratorCallbacks(cWorld & a_World); + } ; + AString m_WorldName; AString m_IniFileName; @@ -713,6 +735,9 @@ private: cChunkGenerator m_Generator; + /** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */ + cChunkGeneratorCallbacks m_GeneratorCallbacks; + cChunkSender m_ChunkSender; cLightingThread m_Lighting; cTickThread m_TickThread; diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt index d431bdf6a..2c83c4662 100644 --- a/src/WorldStorage/CMakeLists.txt +++ b/src/WorldStorage/CMakeLists.txt @@ -9,3 +9,5 @@ file(GLOB SOURCE ) add_library(WorldStorage ${SOURCE}) + +target_link_libraries(WorldStorage OSSupport) diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index e55011069..8f80c3f75 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -16,9 +16,12 @@ #define NBT_RESERVE_SIZE 200 #endif // NBT_RESERVE_SIZE -#define RETURN_FALSE_IF_FALSE(X) do { if (!X) return false; } while (0) - - +#ifdef _MSC_VER + // Dodge a C4127 (conditional expression is constant) for this specific macro usage + #define RETURN_FALSE_IF_FALSE(X) do { if (!X) return false; } while ((false, false)) +#else + #define RETURN_FALSE_IF_FALSE(X) do { if (!X) return false; } while (false) +#endif @@ -80,7 +83,7 @@ bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen) { NEEDBYTES(2); a_StringStart = m_Pos + 2; - a_StringLen = ntohs(*((short *)(m_Data + m_Pos))); + a_StringLen = GetBEShort(m_Data + m_Pos); if (a_StringLen < 0) { // Invalid string length @@ -99,7 +102,7 @@ bool cParsedNBT::ReadCompound(void) // Reads the latest tag as a compound int ParentIdx = m_Tags.size() - 1; int PrevSibling = -1; - while (true) + for (;;) { NEEDBYTES(1); eTagType TagType = (eTagType)(m_Data[m_Pos]); @@ -135,7 +138,7 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) // Read the count: NEEDBYTES(4); - int Count = ntohl(*((int *)(m_Data + m_Pos))); + int Count = GetBEInt(m_Data + m_Pos); m_Pos += 4; if (Count < 0) { @@ -197,7 +200,7 @@ bool cParsedNBT::ReadTag(void) case TAG_ByteArray: { NEEDBYTES(4); - int len = ntohl(*((int *)(m_Data + m_Pos))); + int len = GetBEInt(m_Data + m_Pos); m_Pos += 4; if (len < 0) { @@ -229,7 +232,7 @@ bool cParsedNBT::ReadTag(void) case TAG_IntArray: { NEEDBYTES(4); - int len = ntohl(*((int *)(m_Data + m_Pos))); + int len = GetBEInt(m_Data + m_Pos); m_Pos += 4; if (len < 0) { @@ -276,7 +279,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen for (int Child = m_Tags[a_Tag].m_FirstChild; Child != -1; Child = m_Tags[Child].m_NextSibling) { if ( - (m_Tags[Child].m_NameLength == a_NameLength) && + (m_Tags[Child].m_NameLength == (int)a_NameLength) && (memcmp(m_Data + m_Tags[Child].m_NameStart, a_Name, a_NameLength) == 0) ) { @@ -401,7 +404,7 @@ void cFastNBTWriter::EndList(void) ASSERT(m_Stack[m_CurrentStack].m_Type == TAG_List); // Update the list count: - *((int *)(m_Result.c_str() + m_Stack[m_CurrentStack].m_Pos)) = htonl(m_Stack[m_CurrentStack].m_Count); + SetBEInt((char *)(m_Result.c_str() + m_Stack[m_CurrentStack].m_Pos), m_Stack[m_CurrentStack].m_Count); --m_CurrentStack; } diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index 7323c29cb..b84eda1a1 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -154,13 +154,13 @@ public: inline Int16 GetShort(int a_Tag) const { ASSERT(m_Tags[a_Tag].m_Type == TAG_Short); - return ntohs(*((Int16 *)(m_Data + m_Tags[a_Tag].m_DataStart))); + return GetBEShort(m_Data + m_Tags[a_Tag].m_DataStart); } inline Int32 GetInt(int a_Tag) const { ASSERT(m_Tags[a_Tag].m_Type == TAG_Int); - return ntohl(*((Int32 *)(m_Data + m_Tags[a_Tag].m_DataStart))); + return GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart); } inline Int64 GetLong(int a_Tag) const @@ -172,7 +172,7 @@ public: inline float GetFloat(int a_Tag) const { ASSERT(m_Tags[a_Tag].m_Type == TAG_Float); - Int32 tmp = ntohl(*((Int32 *)(m_Data + m_Tags[a_Tag].m_DataStart))); + Int32 tmp = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart); return *((float *)&tmp); } diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index f290ec128..6aec525a8 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -17,7 +17,6 @@ - /// If a chunk with this Y coord is de-queued, it is a signal to emit the saved-all message (cWorldStorage::QueueSavedMessage()) #define CHUNK_Y_MESSAGE 2 @@ -63,8 +62,6 @@ cWorldStorage::~cWorldStorage() { delete *itr; } // for itr - m_Schemas[] - m_LoadQueue.clear(); - m_SaveQueue.clear(); } @@ -98,18 +95,15 @@ void cWorldStorage::WaitForFinish(void) LOG("Waiting for the world storage to finish saving"); { - // Cancel all loading requests: - cCSLock Lock(m_CSQueues); - m_LoadQueue.clear(); + m_LoadQueue.Clear(); } // Wait for the saving to finish: - WaitForQueuesEmpty(); + WaitForSaveQueueEmpty(); // Wait for the thread to finish: m_ShouldTerminate = true; - m_Event.Set(); - m_evtRemoved.Set(); // Wake up anybody waiting in the WaitForQueuesEmpty() method + m_Event.Set(); // Wake up the thread if waiting super::Wait(); LOG("World storage thread finished"); } @@ -118,34 +112,36 @@ void cWorldStorage::WaitForFinish(void) -void cWorldStorage::WaitForQueuesEmpty(void) +void cWorldStorage::WaitForLoadQueueEmpty(void) { - cCSLock Lock(m_CSQueues); - while (!m_ShouldTerminate && (!m_LoadQueue.empty() || !m_SaveQueue.empty())) - { - cCSUnlock Unlock(Lock); - m_evtRemoved.Wait(); - } + m_LoadQueue.BlockTillEmpty(); +} + + + + + +void cWorldStorage::WaitForSaveQueueEmpty(void) +{ + m_SaveQueue.BlockTillEmpty(); } -int cWorldStorage::GetLoadQueueLength(void) +size_t cWorldStorage::GetLoadQueueLength(void) { - cCSLock Lock(m_CSQueues); - return (int)m_LoadQueue.size(); + return m_LoadQueue.Size(); } -int cWorldStorage::GetSaveQueueLength(void) +size_t cWorldStorage::GetSaveQueueLength(void) { - cCSLock Lock(m_CSQueues); - return (int)m_SaveQueue.size(); + return m_SaveQueue.Size(); } @@ -154,21 +150,7 @@ int cWorldStorage::GetSaveQueueLength(void) void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) { - // Queues the chunk for loading; if not loaded, the chunk will be generated - { - cCSLock Lock(m_CSQueues); - - // Check if already in the queue: - for (sChunkLoadQueue::iterator itr = m_LoadQueue.begin(); itr != m_LoadQueue.end(); ++itr) - { - if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ) && (itr->m_Generate == a_Generate)) - { - return; - } - } - m_LoadQueue.push_back(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); - } - + m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); m_Event.Set(); } @@ -178,11 +160,7 @@ 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) { - { - cCSLock Lock(m_CSQueues); - m_SaveQueue.remove (cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); // Don't add twice - m_SaveQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); - } + m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); m_Event.Set(); } @@ -192,11 +170,8 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::QueueSavedMessage(void) { - // Pushes a special coord pair into the queue, signalizing a message instead: - { - cCSLock Lock(m_CSQueues); - m_SaveQueue.push_back(cChunkCoords(0, CHUNK_Y_MESSAGE, 0)); - } + // Pushes a special coord pair into the queue, signalizing a message instead + m_SaveQueue.EnqueueItem(cChunkCoords(0, CHUNK_Y_MESSAGE, 0)); m_Event.Set(); } @@ -206,18 +181,7 @@ void cWorldStorage::QueueSavedMessage(void) void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - cCSLock Lock(m_CSQueues); - for (sChunkLoadQueue::iterator itr = m_LoadQueue.begin(); itr != m_LoadQueue.end(); ++itr) - { - if ((itr->m_ChunkX != a_ChunkX) || (itr->m_ChunkY != a_ChunkY) || (itr->m_ChunkZ != a_ChunkZ)) - { - continue; - } - m_LoadQueue.erase(itr); - Lock.Unlock(); - m_evtRemoved.Set(); - return; - } // for itr - m_LoadQueue[] + m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ,true)); } @@ -226,11 +190,7 @@ void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk) { - { - cCSLock Lock(m_CSQueues); - m_SaveQueue.remove(a_Chunk); - } - m_evtRemoved.Set(); + m_SaveQueue.Remove(a_Chunk); } @@ -279,21 +239,19 @@ void cWorldStorage::Execute(void) while (!m_ShouldTerminate) { m_Event.Wait(); - // Process both queues until they are empty again: - bool HasMore; + bool Success; do { - HasMore = false; + Success = false; if (m_ShouldTerminate) { return; } - HasMore = LoadOneChunk(); - HasMore = HasMore | SaveOneChunk(); - m_evtRemoved.Set(); - } while (HasMore); + Success = LoadOneChunk(); + Success |= SaveOneChunk(); + } while (Success); } } @@ -304,19 +262,7 @@ void cWorldStorage::Execute(void) bool cWorldStorage::LoadOneChunk(void) { sChunkLoad ToLoad(0, 0, 0, false); - bool HasMore; - bool ShouldLoad = false; - { - cCSLock Lock(m_CSQueues); - if (!m_LoadQueue.empty()) - { - ToLoad = m_LoadQueue.front(); - m_LoadQueue.pop_front(); - ShouldLoad = true; - } - HasMore = !m_LoadQueue.empty(); - } - + bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad); if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ)) { if (ToLoad.m_Generate) @@ -330,7 +276,7 @@ bool cWorldStorage::LoadOneChunk(void) // m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); } } - return HasMore; + return ShouldLoad; } @@ -339,33 +285,24 @@ bool cWorldStorage::LoadOneChunk(void) bool cWorldStorage::SaveOneChunk(void) { - cChunkCoords Save(0, 0, 0); - bool HasMore; - bool ShouldSave = false; - { - cCSLock Lock(m_CSQueues); - if (!m_SaveQueue.empty()) + cChunkCoords ToSave(0, 0, 0); + bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave); + if(ShouldSave) { + if (ToSave.m_ChunkY == CHUNK_Y_MESSAGE) { - Save = m_SaveQueue.front(); - m_SaveQueue.pop_front(); - ShouldSave = true; + LOGINFO("Saved all chunks in world %s", m_World->GetName().c_str()); + return ShouldSave; } - HasMore = !m_SaveQueue.empty(); - } - if (Save.m_ChunkY == CHUNK_Y_MESSAGE) - { - LOGINFO("Saved all chunks in world %s", m_World->GetName().c_str()); - return HasMore; - } - if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkZ)) - { - m_World->MarkChunkSaving(Save.m_ChunkX, Save.m_ChunkZ); - if (m_SaveSchema->SaveChunk(Save)) + if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ)) { - m_World->MarkChunkSaved(Save.m_ChunkX, Save.m_ChunkZ); + m_World->MarkChunkSaving(ToSave.m_ChunkX, ToSave.m_ChunkZ); + if (m_SaveSchema->SaveChunk(ToSave)) + { + m_World->MarkChunkSaved(ToSave.m_ChunkX, ToSave.m_ChunkZ); + } } } - return HasMore; + return ShouldSave; } diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index 007d37571..06cae1717 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -16,6 +16,7 @@ #include "../ChunkDef.h" #include "../OSSupport/IsThread.h" +#include "../OSSupport/Queue.h" @@ -24,6 +25,8 @@ // fwd: class cWorld; +typedef cQueue<cChunkCoords> cChunkCoordsQueue; + @@ -76,10 +79,11 @@ public: bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event void WaitForFinish(void); - void WaitForQueuesEmpty(void); + void WaitForLoadQueueEmpty(void); + void WaitForSaveQueueEmpty(void); - int GetLoadQueueLength(void); - int GetSaveQueueLength(void); + size_t GetLoadQueueLength(void); + size_t GetSaveQueueLength(void); protected: @@ -91,20 +95,30 @@ protected: bool m_Generate; // If true, the chunk will be generated if it cannot be loaded sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} + + bool operator==(const sChunkLoad other) const + { + return this->m_ChunkX == other.m_ChunkX && + this->m_ChunkY == other.m_ChunkY && + this->m_ChunkZ == other.m_ChunkZ; + } } ; - - typedef std::list<sChunkLoad> sChunkLoadQueue; + + struct FuncTable { + static void Delete(sChunkLoad) {}; + static void Combine(sChunkLoad& a_orig, const sChunkLoad a_new) + { + a_orig.m_Generate |= a_new.m_Generate; + }; + }; + + typedef cQueue<sChunkLoad,FuncTable> sChunkLoadQueue; cWorld * m_World; AString m_StorageSchemaName; - - // Both queues are locked by the same CS - cCriticalSection m_CSQueues; + sChunkLoadQueue m_LoadQueue; - cChunkCoordsList m_SaveQueue; - - cEvent m_Event; // Set when there's any addition to the queues - cEvent m_evtRemoved; // Set when an item has been removed from the queue, either by the worker thread or the Unqueue methods + cChunkCoordsQueue m_SaveQueue; /// All the storage schemas (all used for loading) cWSSchemaList m_Schemas; @@ -116,6 +130,8 @@ protected: virtual void Execute(void) override; + cEvent m_Event; // Set when there's any addition to the queues + /// Loads one chunk from the queue (if any queued); returns true if there are more chunks in the load queue bool LoadOneChunk(void); diff --git a/src/main.cpp b/src/main.cpp index 81c6b41e4..0620e0f0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,6 +50,11 @@ void NonCtrlHandler(int a_Signal) LOGWARN("Segmentation fault; MCServer has crashed :("); exit(EXIT_FAILURE); } + case SIGTERM: + { + std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it... + break; + } default: break; } } |