From da58620d45bf5d7d31f6d3700aa6687e17d0d1c8 Mon Sep 17 00:00:00 2001 From: tycho Date: Sat, 9 May 2015 13:16:07 +0100 Subject: Added TCLAP --- .gitmodules | 3 +++ lib/TCLAP | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/TCLAP diff --git a/.gitmodules b/.gitmodules index 93fac9d1f..20f8ea103 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "lib/libevent"] path = lib/libevent url = https://github.com/mc-server/libevent.git +[submodule "lib/TCLAP"] + path = lib/TCLAP + url = https://github.com/mc-server/TCLAP.git diff --git a/lib/TCLAP b/lib/TCLAP new file mode 160000 index 000000000..12cee3878 --- /dev/null +++ b/lib/TCLAP @@ -0,0 +1 @@ +Subproject commit 12cee38782897cfe60a1611615c200c45cd99eaf -- cgit v1.2.3 From b9efa02c80b54e044326771bbffdddf206daef2e Mon Sep 17 00:00:00 2001 From: tycho Date: Thu, 14 May 2015 15:47:51 +0100 Subject: Initial implementation of IniFile overloading --- src/Bindings/PluginManager.cpp | 38 +++-- src/Bindings/PluginManager.h | 11 +- src/CMakeLists.txt | 6 + src/Globals.h | 2 +- src/IniFile.cpp | 51 ++++-- src/IniFile.h | 26 +-- src/MemorySettingsRepository.cpp | 312 ++++++++++++++++++++++++++++++++++++ src/MemorySettingsRepository.h | 80 +++++++++ src/OverridesSettingsRepository.cpp | 273 +++++++++++++++++++++++++++++++ src/OverridesSettingsRepository.h | 52 ++++++ src/Protocol/Authenticator.cpp | 12 +- src/Protocol/Authenticator.h | 6 +- src/Protocol/MojangAPI.cpp | 10 +- src/Protocol/MojangAPI.h | 4 +- src/RCONServer.cpp | 8 +- src/RCONServer.h | 4 +- src/Root.cpp | 57 +++---- src/Root.h | 5 +- src/Server.cpp | 22 +-- src/Server.h | 4 +- src/SettingsRepositoryInterface.h | 46 ++++++ src/main.cpp | 42 ++++- 22 files changed, 955 insertions(+), 116 deletions(-) create mode 100644 src/MemorySettingsRepository.cpp create mode 100644 src/MemorySettingsRepository.h create mode 100644 src/OverridesSettingsRepository.cpp create mode 100644 src/OverridesSettingsRepository.h create mode 100644 src/SettingsRepositoryInterface.h diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index db2493955..86be30938 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -118,7 +118,7 @@ void cPluginManager::ReloadPluginsNow(void) -void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) +void cPluginManager::ReloadPluginsNow(cSettingsRepositoryInterface & a_Settings) { LOG("-- Loading Plugins --"); @@ -130,7 +130,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) RefreshPluginList(); // Load the plugins: - AStringVector ToLoad = GetFoldersToLoad(a_SettingsIni); + AStringVector ToLoad = GetFoldersToLoad(a_Settings); for (auto & pluginFolder: ToLoad) { LoadPlugin(pluginFolder); @@ -157,16 +157,16 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) -void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni) +void cPluginManager::InsertDefaultPlugins(cSettingsRepositoryInterface & a_Settings) { - a_SettingsIni.AddKeyName("Plugins"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=Debuggers"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=HookNotify"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=ChunkWorx"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=APIDump"); - a_SettingsIni.AddValue("Plugins", "Plugin", "Core"); - a_SettingsIni.AddValue("Plugins", "Plugin", "TransAPI"); - a_SettingsIni.AddValue("Plugins", "Plugin", "ChatLog"); + a_Settings.AddKeyName("Plugins"); + a_Settings.AddKeyComment("Plugins", " Plugin=Debuggers"); + a_Settings.AddKeyComment("Plugins", " Plugin=HookNotify"); + a_Settings.AddKeyComment("Plugins", " Plugin=ChunkWorx"); + a_Settings.AddKeyComment("Plugins", " Plugin=APIDump"); + a_Settings.AddValue("Plugins", "Plugin", "Core"); + a_Settings.AddValue("Plugins", "Plugin", "TransAPI"); + a_Settings.AddValue("Plugins", "Plugin", "ChatLog"); } @@ -1896,25 +1896,23 @@ size_t cPluginManager::GetNumLoadedPlugins(void) const -AStringVector cPluginManager::GetFoldersToLoad(cIniFile & a_SettingsIni) +AStringVector cPluginManager::GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings) { // Check if the Plugins section exists. - int KeyNum = a_SettingsIni.FindKey("Plugins"); - if (KeyNum == -1) + if (a_Settings.KeyExists("Plugins")) { - InsertDefaultPlugins(a_SettingsIni); - KeyNum = a_SettingsIni.FindKey("Plugins"); + InsertDefaultPlugins(a_Settings); } // Get the list of plugins to load: AStringVector res; - int NumPlugins = a_SettingsIni.GetNumValues(KeyNum); - for (int i = 0; i < NumPlugins; i++) + auto Values = a_Settings.GetValues("Plugins"); + for (auto NameValue : Values) { - AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); + AString ValueName = NameValue.first; if (ValueName.compare("Plugin") == 0) { - AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); + AString PluginFile = NameValue.second; if (!PluginFile.empty()) { res.push_back(PluginFile); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index d8c886b62..faabf3aec 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -24,6 +24,7 @@ class cPlayer; class cPlugin; class cProjectileEntity; class cWorld; +class cSettingsRepositoryInterface; struct TakeDamageInfo; typedef SharedPtr cPluginPtr; @@ -364,20 +365,20 @@ private: /** Reloads all plugins, defaulting to settings.ini for settings location */ void ReloadPluginsNow(void); - /** Reloads all plugins with a cIniFile object expected to be initialised to settings.ini */ - void ReloadPluginsNow(cIniFile & a_SettingsIni); + /** Reloads all plugins with a settings repo expected to be initialised to settings.ini */ + void ReloadPluginsNow(cSettingsRepositoryInterface & a_Settings); /** Unloads all plugins */ void UnloadPluginsNow(void); - /** Handles writing default plugins if 'Plugins' key not found using a cIniFile object expected to be intialised to settings.ini */ - void InsertDefaultPlugins(cIniFile & a_SettingsIni); + /** Handles writing default plugins if 'Plugins' key not found using a settings repo expected to be intialised to settings.ini */ + void InsertDefaultPlugins(cSettingsRepositoryInterface & a_Settings); /** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns crExecuted if the command is executed. */ CommandResult HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); /** Returns the folders that are specified in the settings ini to load plugins from. */ - AStringVector GetFoldersToLoad(cIniFile & a_SettingsIni); + AStringVector GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings); } ; // tolua_export diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e367bcf5..25de24c91 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,11 +48,13 @@ SET (SRCS Logger.cpp Map.cpp MapManager.cpp + MemorySettingsRepository.cpp MobCensus.cpp MobFamilyCollecter.cpp MobProximityCounter.cpp MobSpawner.cpp MonsterConfig.cpp + OverridesSettingsRepository.cpp ProbabDistrib.cpp RankManager.cpp RCONServer.cpp @@ -116,11 +118,13 @@ SET (HDRS Map.h MapManager.h Matrix4.h + MemorySettingsRepository.h MobCensus.h MobFamilyCollecter.h MobProximityCounter.h MobSpawner.h MonsterConfig.h + OverridesSettingsRepository.h ProbabDistrib.h RankManager.h RCONServer.h @@ -128,6 +132,7 @@ SET (HDRS Scoreboard.h Server.h SetChunkData.h + SettingsRepositoryInterface.h Statistics.h StringCompression.h StringUtils.h @@ -142,6 +147,7 @@ SET (HDRS include_directories(".") include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/sqlite") include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/SQLiteCpp/include") +include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/TCLAP/include") configure_file("BuildInfo.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.h") diff --git a/src/Globals.h b/src/Globals.h index 1f354ae77..cee2094bc 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -436,7 +436,7 @@ typename std::enable_if::value, C>::type CeilC(T a_Value) template std::unique_ptr make_unique(Args&&... args) { - return std::unique_ptr(new T(args...)); + return std::unique_ptr(new T(std::forward(args)...)); } // a tick is 50 ms diff --git a/src/IniFile.cpp b/src/IniFile.cpp index 99c0a5f0f..8dab87d15 100644 --- a/src/IniFile.cpp +++ b/src/IniFile.cpp @@ -49,6 +49,9 @@ cIniFile::cIniFile(void) : bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) { + + m_Filename = a_FileName; + // Normally you would use ifstream, but the SGI CC compiler has // a few bugs with ifstream. So ... fstream used. fstream f; @@ -56,7 +59,8 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) AString keyname, valuename, value; AString::size_type pLeft, pRight; bool IsFromExampleRedirect = false; - + + f.open((FILE_IO_PREFIX + a_FileName).c_str(), ios::in); if (f.fail()) { @@ -650,7 +654,7 @@ void cIniFile::Clear(void) -bool cIniFile::HasValue(const AString & a_KeyName, const AString & a_ValueName) +bool cIniFile::HasValue(const AString & a_KeyName, const AString & a_ValueName) const { // Find the key: int keyID = FindKey(a_KeyName); @@ -889,8 +893,36 @@ void cIniFile::RemoveBom(AString & a_line) const +bool cIniFile::KeyExists(AString a_keyname) const +{ + return FindKey(a_keyname) != noID; +} + + + + + +std::vector> cIniFile::GetValues(AString a_keyName) +{ + std::vector> ret; + int keyID = FindKey(a_keyName); + if (keyID == noID) + { + return ret; + } + for (size_t valueID = 0; valueID < keys[keyID].names.size(); ++valueID) + { + ret.emplace_back(keys[keyID].names[valueID], keys[keyID].values[valueID]); + } + return ret; +} + + + + + AStringVector ReadUpgradeIniPorts( - cIniFile & a_IniFile, + cSettingsRepositoryInterface & a_Settings, const AString & a_KeyName, const AString & a_PortsValueName, const AString & a_OldIPv4ValueName, @@ -899,23 +931,23 @@ AStringVector ReadUpgradeIniPorts( ) { // Read the regular value, but don't use the default (in order to detect missing value for upgrade): - AStringVector Ports = StringSplitAndTrim(a_IniFile.GetValue(a_KeyName, a_PortsValueName), ";,"); + AStringVector Ports = StringSplitAndTrim(a_Settings.GetValue(a_KeyName, a_PortsValueName), ";,"); if (Ports.empty()) { // Historically there were two separate entries for IPv4 and IPv6, merge them and migrate: - AString Ports4 = a_IniFile.GetValue(a_KeyName, a_OldIPv4ValueName, a_DefaultValue); - AString Ports6 = a_IniFile.GetValue(a_KeyName, a_OldIPv6ValueName); + AString Ports4 = a_Settings.GetValue(a_KeyName, a_OldIPv4ValueName, a_DefaultValue); + AString Ports6 = a_Settings.GetValue(a_KeyName, a_OldIPv6ValueName); Ports = MergeStringVectors(StringSplitAndTrim(Ports4, ";,"), StringSplitAndTrim(Ports6, ";,")); - a_IniFile.DeleteValue(a_KeyName, a_OldIPv4ValueName); - a_IniFile.DeleteValue(a_KeyName, a_OldIPv6ValueName); + a_Settings.DeleteValue(a_KeyName, a_OldIPv4ValueName); + a_Settings.DeleteValue(a_KeyName, a_OldIPv6ValueName); // If those weren't present or were empty, use the default:" if (Ports.empty()) { Ports = StringSplitAndTrim(a_DefaultValue, ";,"); } - a_IniFile.SetValue(a_KeyName, a_PortsValueName, StringsConcat(Ports, ',')); + a_Settings.SetValue(a_KeyName, a_PortsValueName, StringsConcat(Ports, ',')); } return Ports; @@ -923,4 +955,3 @@ AStringVector ReadUpgradeIniPorts( - diff --git a/src/IniFile.h b/src/IniFile.h index 71fea3a00..861be3800 100644 --- a/src/IniFile.h +++ b/src/IniFile.h @@ -18,7 +18,7 @@ #pragma once - +#include "SettingsRepositoryInterface.h" #define MAX_KEYNAME 128 #define MAX_VALUENAME 128 @@ -30,10 +30,12 @@ // tolua_begin -class cIniFile +class cIniFile : public cSettingsRepositoryInterface { private: bool m_IsCaseInsensitive; + + AString m_Filename; struct key { @@ -53,15 +55,19 @@ private: void RemoveBom(AString & a_line) const; public: - - enum errors - { - noID = -1, - }; /// Creates a new instance with no data cIniFile(void); +// tolua_end + virtual ~cIniFile() = default; + + virtual std::vector> GetValues(AString a_keyName) override; + + virtual bool KeyExists(const AString a_keyName) const override; + +// tolua_begin + // Sets whether or not keynames and valuenames should be case sensitive. // The default is case insensitive. void CaseSensitive (void) { m_IsCaseInsensitive = false; } @@ -77,11 +83,13 @@ public: /// Writes data stored in class to the specified ini file bool WriteFile(const AString & a_FileName) const; + virtual bool Flush() override { return WriteFile(m_Filename); } + /// Deletes all stored ini data (but doesn't touch the file) void Clear(void); /** Returns true iff the specified value exists. */ - bool HasValue(const AString & a_KeyName, const AString & a_ValueName); + bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const; /// Returns index of specified key, or noID if not found int FindKey(const AString & keyname) const; @@ -222,7 +230,7 @@ Reads the list of ports from a_PortsValueName. If that value doesn't exist or is in a_OldIPv4ValueName and a_OldIPv6ValueName; in this case the old values are removed from the INI file. If there is none of the three values or they are all empty, the default is used and stored in the Ports value. */ AStringVector ReadUpgradeIniPorts( - cIniFile & a_IniFile, + cSettingsRepositoryInterface & a_Settings, const AString & a_KeyName, const AString & a_PortsValueName, const AString & a_OldIPv4ValueName, diff --git a/src/MemorySettingsRepository.cpp b/src/MemorySettingsRepository.cpp new file mode 100644 index 000000000..21b4c769c --- /dev/null +++ b/src/MemorySettingsRepository.cpp @@ -0,0 +1,312 @@ + +#include "Globals.h" + +#include "MemorySettingsRepository.h" + + + + +bool cMemorySettingsRepository::KeyExists(const AString keyname) const +{ + return m_Map.count(keyname) != 0; +} + + + + + +bool cMemorySettingsRepository::HasValue(const AString & a_KeyName, const AString & a_ValueName) const +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + return false; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + return false; + } + return true; +} + + + + +int cMemorySettingsRepository::AddKeyName(const AString & a_keyname) +{ + m_Map.emplace(a_keyname, std::unordered_multimap{}); + return 0; +} + + + + + +bool cMemorySettingsRepository::AddKeyComment(const AString & keyname, const AString & comment) +{ + return false; +} + + + + + +AString cMemorySettingsRepository::GetKeyComment(const AString & keyname, const int commentID) const +{ + return ""; +} + + + + + +bool cMemorySettingsRepository::DeleteKeyComment(const AString & keyname, const int commentID) +{ + return false; +} + + + + + + +void cMemorySettingsRepository::AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) +{ + if (m_Writable) + { + m_Map[a_KeyName].emplace(a_ValueName, sValue(a_Value)); + } +} + + + + +void cMemorySettingsRepository::AddValue (const AString & a_KeyName, const AString & a_ValueName, Int64 a_Value) +{ + if (m_Writable) + { + m_Map[a_KeyName].emplace(a_ValueName, sValue(a_Value)); + } +} + + + + + +void cMemorySettingsRepository::AddValue (const AString & a_KeyName, const AString & a_ValueName, bool a_Value) +{ + if (m_Writable) + { + m_Map[a_KeyName].emplace(a_ValueName, sValue(a_Value)); + } +} + + + + + +std::vector> cMemorySettingsRepository::GetValues(AString a_keyName) +{ + std::vector> ret; + for (auto pair : m_Map[a_keyName]) + { + ret.emplace_back(pair.first, pair.second.getStringValue()); + } + return ret; +} + + + + + +AString cMemorySettingsRepository::GetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & defValue) const +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + return defValue; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + return defValue; + } + return iter->second.getStringValue(); +} + + + + + +AString cMemorySettingsRepository::GetValueSet (const AString & a_KeyName, const AString & a_ValueName, const AString & defValue) +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + return iter->second.getStringValue(); +} + + + + + +int cMemorySettingsRepository::GetValueSetI(const AString & a_KeyName, const AString & a_ValueName, const int defValue) +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + AddValue(a_KeyName, a_ValueName, static_cast(defValue)); + return defValue; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + AddValue(a_KeyName, a_ValueName, static_cast(defValue)); + return defValue; + } + return static_cast(iter->second.getIntValue()); +} + + + + + +Int64 cMemorySettingsRepository::GetValueSetI(const AString & a_KeyName, const AString & a_ValueName, const Int64 defValue) +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + return iter->second.getIntValue(); +} + + + + +bool cMemorySettingsRepository::GetValueSetB(const AString & a_KeyName, const AString & a_ValueName, const bool defValue) +{ + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + AddValue(a_KeyName, a_ValueName, defValue); + return defValue; + } + return iter->second.getBoolValue(); +} + + + + + +bool cMemorySettingsRepository::SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists) +{ + if (!m_Writable) + { + return false; + } + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + if (a_CreateIfNotExists) + { + AddValue(a_KeyName, a_ValueName, a_Value); + } + return a_CreateIfNotExists; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + if (a_CreateIfNotExists) + { + AddValue(a_KeyName, a_ValueName, a_Value); + } + return a_CreateIfNotExists; + } + iter->second = sValue(a_Value); + return true; +} + + + + +bool cMemorySettingsRepository::SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists) +{ + if (!m_Writable) + { + return false; + } + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + if (a_CreateIfNotExists) + { + AddValue(a_KeyName, a_ValueName, static_cast(a_Value)); + } + return a_CreateIfNotExists; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + if (a_CreateIfNotExists) + { + AddValue(a_KeyName, a_ValueName, static_cast(a_Value)); + } + return a_CreateIfNotExists; + } + iter->second = sValue(static_cast(a_Value)); + return true; +} + + + + + +bool cMemorySettingsRepository::DeleteValue(const AString & a_KeyName, const AString & a_ValueName) +{ + if (!m_Writable) + { + return false; + } + auto outerIter = m_Map.find(a_KeyName); + if (outerIter == m_Map.end()) + { + return false; + } + auto iter = outerIter->second.find(a_ValueName); + if (iter == outerIter->second.end()) + { + return false; + } + outerIter->second.erase(iter); + return true; +} + +bool cMemorySettingsRepository::Flush() +{ + return true; +} + diff --git a/src/MemorySettingsRepository.h b/src/MemorySettingsRepository.h new file mode 100644 index 000000000..335bc4513 --- /dev/null +++ b/src/MemorySettingsRepository.h @@ -0,0 +1,80 @@ + +#pragma once + +#include "SettingsRepositoryInterface.h" + +#include + +class cMemorySettingsRepository : public cSettingsRepositoryInterface +{ +public: + + virtual bool KeyExists(const AString keyname) const override; + + virtual bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const override; + + virtual int AddKeyName(const AString & keyname) override; + + virtual bool AddKeyComment(const AString & keyname, const AString & comment) override; + + virtual AString GetKeyComment(const AString & keyname, const int commentID) const override; + + virtual bool DeleteKeyComment(const AString & keyname, const int commentID) override; + + virtual void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) override; + void AddValue (const AString & a_KeyName, const AString & a_ValueName, const Int64 a_Value); + void AddValue (const AString & a_KeyName, const AString & a_ValueName, const bool a_Value); + + virtual std::vector> GetValues(AString a_keyName) override; + + virtual AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const override; + + + virtual AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = "") override; + virtual int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0) override; + virtual Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0) override; + virtual bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) override; + + virtual bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true) override; + virtual bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true) override; + + virtual bool DeleteValue(const AString & keyname, const AString & valuename) override; + + virtual bool Flush() override; + + void SetReadOnly() + { + m_Writable = false; + } + +private: + + bool m_Writable = true; + + struct sValue + { + sValue(AString value) : m_Type(eType::String), m_stringValue (value) {} + sValue(Int64 value) : m_Type(eType::Int64), m_intValue(value) {} + sValue(bool value) : m_Type(eType::Bool), m_boolValue(value) {} + + AString getStringValue() const { ASSERT(m_Type == eType::String); return m_stringValue; } + Int64 getIntValue() const { ASSERT(m_Type == eType::Int64); return m_intValue; } + bool getBoolValue() const { ASSERT(m_Type == eType::Bool); return m_boolValue; } + private: + enum class eType + { + String, + Int64, + Bool + } m_Type; + AString m_stringValue; + union + { + Int64 m_intValue; + bool m_boolValue; + }; + }; + + std::unordered_map> m_Map{}; +}; + diff --git a/src/OverridesSettingsRepository.cpp b/src/OverridesSettingsRepository.cpp new file mode 100644 index 000000000..6defdd6b5 --- /dev/null +++ b/src/OverridesSettingsRepository.cpp @@ -0,0 +1,273 @@ + +#include "Globals.h" +#include "OverridesSettingsRepository.h" + +cOverridesSettingsRepository::cOverridesSettingsRepository(std::unique_ptr a_Main, std::unique_ptr a_Overrides) : + m_Main(std::move(a_Main)), + m_Overrides(std::move(a_Overrides)) +{ +} + + + + + +bool cOverridesSettingsRepository::KeyExists(const AString a_keyName) const +{ + return m_Overrides->KeyExists(a_keyName) || m_Main->KeyExists(a_keyName); +} + + + + +bool cOverridesSettingsRepository::HasValue(const AString & a_KeyName, const AString & a_ValueName) const +{ + return m_Overrides->HasValue(a_KeyName, a_ValueName) || m_Main->HasValue(a_KeyName, a_ValueName); +} + + + + + +int cOverridesSettingsRepository::AddKeyName(const AString & a_keyname) +{ + + if (m_Overrides->KeyExists(a_keyname)) + { + m_Overrides->AddKeyName(a_keyname); + return 0; + } + + return m_Main->AddKeyName(a_keyname); +} + + + + + +bool cOverridesSettingsRepository::AddKeyComment(const AString & a_keyname, const AString & a_comment) +{ + if (m_Overrides->KeyExists(a_keyname)) + { + return m_Overrides->AddKeyComment(a_keyname, a_comment); + } + + return m_Main->AddKeyComment(a_keyname, a_comment); +} + + + + + +AString cOverridesSettingsRepository::GetKeyComment(const AString & a_keyname, const int a_commentID) const +{ + + if (m_Overrides->KeyExists(a_keyname)) + { + return m_Overrides->GetKeyComment(a_keyname, a_commentID); + } + + return m_Main->GetKeyComment(a_keyname, a_commentID); +} + + + + + +bool cOverridesSettingsRepository::DeleteKeyComment(const AString & a_keyname, const int a_commentID) +{ + if (m_Overrides->KeyExists(a_keyname)) + { + return m_Overrides->DeleteKeyComment(a_keyname, a_commentID); + } + + return m_Main->DeleteKeyComment(a_keyname, a_commentID); +} + + + + + +void cOverridesSettingsRepository::AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + m_Overrides->AddValue(a_KeyName, a_ValueName, a_Value); + } + else + { + m_Main->AddValue(a_KeyName, a_ValueName, a_Value); + } +} + + + + + +std::vector> cOverridesSettingsRepository::GetValues(AString a_keyName) +{ + auto overrides = m_Overrides->GetValues(a_keyName); + auto main = m_Main->GetValues(a_keyName); + std::sort(overrides.begin(), overrides.end(), [](std::pair a, std::pair b) -> bool { return a < b ;}); + std::sort(main.begin(), main.end(), [](std::pair a, std::pair b) -> bool { return a < b ;}); + + std::vector> ret; + + + size_t overridesIndex = 0; + for (auto pair : main) + { + if (overridesIndex >= overrides.size()) + { + ret.push_back(pair); + continue; + } + if (pair.first == overrides[overridesIndex].first) + { + continue; + } + while (pair.first > overrides[overridesIndex].first) + { + ret.push_back(overrides[overridesIndex]); + overridesIndex++; + } + ret.push_back(pair); + } + return ret; +} + + + + + +AString cOverridesSettingsRepository::GetValue(const AString & a_KeyName, const AString & a_ValueName, const AString & defValue) const +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->GetValue(a_KeyName, a_ValueName, defValue); + } + else + { + return m_Main->GetValue(a_KeyName, a_ValueName, defValue); + } +} + + + + + +AString cOverridesSettingsRepository::GetValueSet (const AString & a_KeyName, const AString & a_ValueName, const AString & defValue) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->GetValueSet(a_KeyName, a_ValueName, defValue); + } + else + { + return m_Main->GetValueSet(a_KeyName, a_ValueName, defValue); + } +} + + + + + +int cOverridesSettingsRepository::GetValueSetI(const AString & a_KeyName, const AString & a_ValueName, const int defValue) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->GetValueSetI(a_KeyName, a_ValueName, defValue); + } + else + { + return m_Main->GetValueSetI(a_KeyName, a_ValueName, defValue); + } +} + + + + + +Int64 cOverridesSettingsRepository::GetValueSetI(const AString & a_KeyName, const AString & a_ValueName, const Int64 defValue) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->GetValueSetI(a_KeyName, a_ValueName, defValue); + } + else + { + return m_Main->GetValueSetI(a_KeyName, a_ValueName, defValue); + } +} + + + + + +bool cOverridesSettingsRepository::GetValueSetB(const AString & a_KeyName, const AString & a_ValueName, const bool defValue) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->GetValueSetB(a_KeyName, a_ValueName, defValue); + } + else + { + return m_Main->GetValueSetB(a_KeyName, a_ValueName, defValue); + } +} + + + + + +bool cOverridesSettingsRepository::SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->SetValue(a_KeyName, a_ValueName, a_Value, a_CreateIfNotExists); + } + else + { + return m_Main->SetValue(a_KeyName, a_ValueName, a_Value, a_CreateIfNotExists); + } +} + + + + + +bool cOverridesSettingsRepository::SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->SetValueI(a_KeyName, a_ValueName, a_Value, a_CreateIfNotExists); + } + else + { + return m_Main->SetValueI(a_KeyName, a_ValueName, a_Value, a_CreateIfNotExists); + } +} + + + + + +bool cOverridesSettingsRepository::DeleteValue(const AString & a_KeyName, const AString & a_ValueName) +{ + if (m_Overrides->HasValue(a_KeyName, a_ValueName)) + { + return m_Overrides->DeleteValue(a_KeyName, a_ValueName); + } + else + { + return m_Overrides->DeleteValue(a_KeyName, a_ValueName); + } +} + + + +bool cOverridesSettingsRepository::Flush() +{ + return m_Overrides->Flush() && m_Main->Flush(); +} + diff --git a/src/OverridesSettingsRepository.h b/src/OverridesSettingsRepository.h new file mode 100644 index 000000000..04a53997f --- /dev/null +++ b/src/OverridesSettingsRepository.h @@ -0,0 +1,52 @@ + +#pragma once + +#include "SettingsRepositoryInterface.h" + +#include + +class cOverridesSettingsRepository : public cSettingsRepositoryInterface +{ + +public: + cOverridesSettingsRepository(std::unique_ptr a_Main, std::unique_ptr a_Overrides); + + virtual ~cOverridesSettingsRepository() = default; + + virtual bool KeyExists(const AString keyname) const override; + + virtual bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const override; + + virtual int AddKeyName(const AString & keyname) override; + + virtual bool AddKeyComment(const AString & keyname, const AString & comment) override; + + virtual AString GetKeyComment(const AString & keyname, const int commentID) const override; + + virtual bool DeleteKeyComment(const AString & keyname, const int commentID) override; + + virtual void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) override; + + virtual std::vector> GetValues(AString a_keyName) override; + + virtual AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const override; + + virtual AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = "") override; + virtual int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0) override; + virtual Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0) override; + virtual bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) override; + + virtual bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true) override; + virtual bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true) override; + + virtual bool DeleteValue(const AString & keyname, const AString & valuename) override; + + virtual bool Flush() override; + +private: + + std::unique_ptr m_Main; + std::unique_ptr m_Overrides; + +}; + diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index c9e4296a2..294b6e9be 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -40,11 +40,11 @@ cAuthenticator::~cAuthenticator() -void cAuthenticator::ReadINI(cIniFile & IniFile) +void cAuthenticator::ReadSettings(cSettingsRepositoryInterface & a_Settings) { - m_Server = IniFile.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER); - m_Address = IniFile.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS); - m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); + m_Server = a_Settings.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER); + m_Address = a_Settings.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS); + m_ShouldAuthenticate = a_Settings.GetValueSetB("Authentication", "Authenticate", true); } @@ -69,9 +69,9 @@ void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, co -void cAuthenticator::Start(cIniFile & IniFile) +void cAuthenticator::Start(cSettingsRepositoryInterface & a_Settings) { - ReadINI(IniFile); + ReadSettings(a_Settings); m_ShouldTerminate = false; super::Start(); } diff --git a/src/Protocol/Authenticator.h b/src/Protocol/Authenticator.h index 853eff535..02b349256 100644 --- a/src/Protocol/Authenticator.h +++ b/src/Protocol/Authenticator.h @@ -14,7 +14,7 @@ #include "../OSSupport/IsThread.h" - +class cSettingsRepositoryInterface; @@ -40,13 +40,13 @@ public: ~cAuthenticator(); /** (Re-)read server and address from INI: */ - void ReadINI(cIniFile & IniFile); + void ReadSettings(cSettingsRepositoryInterface & a_Settings); /** Queues a request for authenticating a user. If the auth fails, the user will be kicked */ void Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash); /** Starts the authenticator thread. The thread may be started and stopped repeatedly */ - void Start(cIniFile & IniFile); + void Start(cSettingsRepositoryInterface & a_Settings); /** Stops the authenticator thread. The thread may be started and stopped repeatedly */ void Stop(void); diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 0d1441500..51b8e90e7 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -226,12 +226,12 @@ cMojangAPI::~cMojangAPI() -void cMojangAPI::Start(cIniFile & a_SettingsIni, bool a_ShouldAuth) +void cMojangAPI::Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth) { - m_NameToUUIDServer = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); - m_NameToUUIDAddress = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); - m_UUIDToProfileServer = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER); - m_UUIDToProfileAddress = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS); + m_NameToUUIDServer = a_Settings.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); + m_NameToUUIDAddress = a_Settings.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); + m_UUIDToProfileServer = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER); + m_UUIDToProfileAddress = a_Settings.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS); LoadCachesFromDisk(); if (a_ShouldAuth) { diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 0dc2617b6..bea950740 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -25,7 +25,7 @@ namespace Json - +class cSettingsRepositoryInterface; // tolua_begin class cMojangAPI @@ -38,7 +38,7 @@ public: /** Initializes the API; reads the settings from the specified ini file. Loads cached results from disk. */ - void Start(cIniFile & a_SettingsIni, bool a_ShouldAuth); + void Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth); /** Connects to the specified server using SSL, sends the given request and receives the response. Checks Mojang certificates using the hard-coded Starfield root CA certificate. diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index 685bd92f5..c5dc9b69b 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -134,15 +134,15 @@ cRCONServer::~cRCONServer() -void cRCONServer::Initialize(cIniFile & a_IniFile) +void cRCONServer::Initialize(cSettingsRepositoryInterface & a_Settings) { - if (!a_IniFile.GetValueSetB("RCON", "Enabled", false)) + if (!a_Settings.GetValueSetB("RCON", "Enabled", false)) { return; } // Read the password, don't allow an empty one: - m_Password = a_IniFile.GetValueSet("RCON", "Password", ""); + m_Password = a_Settings.GetValueSet("RCON", "Password", ""); if (m_Password.empty()) { LOGWARNING("RCON is requested, but the password is not set. RCON is now disabled."); @@ -150,7 +150,7 @@ void cRCONServer::Initialize(cIniFile & a_IniFile) } // Read the listening ports for RCON from config: - AStringVector Ports = ReadUpgradeIniPorts(a_IniFile, "RCON", "Ports", "PortsIPv4", "PortsIPv6", "25575"); + AStringVector Ports = ReadUpgradeIniPorts(a_Settings, "RCON", "Ports", "PortsIPv4", "PortsIPv6", "25575"); // Start listening on each specified port: for (auto port: Ports) diff --git a/src/RCONServer.h b/src/RCONServer.h index 352fa7b50..81b019516 100644 --- a/src/RCONServer.h +++ b/src/RCONServer.h @@ -17,7 +17,7 @@ // fwd: class cServer; -class cIniFile; +class cSettingsRepositoryInterface; @@ -29,7 +29,7 @@ public: cRCONServer(cServer & a_Server); virtual ~cRCONServer(); - void Initialize(cIniFile & a_IniFile); + void Initialize(cSettingsRepositoryInterface & a_Settings); protected: friend class cRCONCommandOutput; diff --git a/src/Root.cpp b/src/Root.cpp index 349608e8d..de53e0cd8 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -19,6 +19,8 @@ #include "LoggerListeners.h" #include "BuildInfo.h" #include "IniFile.h" +#include "SettingsRepositoryInterface.h" +#include "OverridesSettingsRepository.h" #ifdef _WIN32 #include @@ -96,7 +98,7 @@ void cRoot::InputThread(cRoot & a_Params) -void cRoot::Start(void) +void cRoot::Start(std::unique_ptr overridesRepo) { #ifdef _WIN32 HWND hwnd = GetConsoleWindow(); @@ -130,22 +132,24 @@ void cRoot::Start(void) m_Server = new cServer(); LOG("Reading server config..."); - cIniFile IniFile; - if (!IniFile.ReadFile("settings.ini")) + + auto IniFile = make_unique(); + if (!IniFile->ReadFile("settings.ini")) { LOGWARN("Regenerating settings.ini, all settings will be reset"); - IniFile.AddHeaderComment(" This is the main server configuration"); - IniFile.AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini"); - IniFile.AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help"); + IniFile->AddHeaderComment(" This is the main server configuration"); + IniFile->AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini"); + IniFile->AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help"); } + auto settingsRepo = make_unique(std::move(IniFile), std::move(overridesRepo)); LOG("Starting server..."); m_MojangAPI = new cMojangAPI; - bool ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); - m_MojangAPI->Start(IniFile, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init - if (!m_Server->InitServer(IniFile, ShouldAuthenticate)) + bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true); + m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init + if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate)) { - IniFile.WriteFile("settings.ini"); + settingsRepo->Flush(); LOGERROR("Failure starting server, aborting..."); return; } @@ -160,29 +164,29 @@ void cRoot::Start(void) m_FurnaceRecipe = new cFurnaceRecipe(); LOGD("Loading worlds..."); - LoadWorlds(IniFile); + LoadWorlds(*settingsRepo); LOGD("Loading plugin manager..."); m_PluginManager = new cPluginManager(); - m_PluginManager->ReloadPluginsNow(IniFile); + m_PluginManager->ReloadPluginsNow(*settingsRepo); LOGD("Loading MonsterConfig..."); m_MonsterConfig = new cMonsterConfig; // This sets stuff in motion LOGD("Starting Authenticator..."); - m_Authenticator.Start(IniFile); + m_Authenticator.Start(*settingsRepo); LOGD("Starting worlds..."); StartWorlds(); - if (IniFile.GetValueSetB("DeadlockDetect", "Enabled", true)) + if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true)) { LOGD("Starting deadlock detector..."); - dd.Start(IniFile.GetValueSetI("DeadlockDetect", "IntervalSec", 20)); + dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20)); } - IniFile.WriteFile("settings.ini"); + settingsRepo->Flush(); LOGD("Finalising startup..."); if (m_Server->Start()) @@ -282,30 +286,29 @@ void cRoot::LoadGlobalSettings() -void cRoot::LoadWorlds(cIniFile & IniFile) +void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings) { // First get the default world - AString DefaultWorldName = IniFile.GetValueSet("Worlds", "DefaultWorld", "world"); + AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds - int KeyNum = IniFile.FindKey("Worlds"); - int NumWorlds = IniFile.GetNumValues(KeyNum); - if (NumWorlds <= 0) + auto Worlds = a_Settings.GetValues("Worlds"); + if (Worlds.size() <= 0) { return; } bool FoundAdditionalWorlds = false; - for (int i = 0; i < NumWorlds; i++) + for (auto WorldNameValue : Worlds) { - AString ValueName = IniFile.GetValueName(KeyNum, i); + AString ValueName = WorldNameValue.first; if (ValueName.compare("World") != 0) { continue; } - AString WorldName = IniFile.GetValue(KeyNum, i); + AString WorldName = WorldNameValue.second; if (WorldName.empty()) { continue; @@ -317,10 +320,10 @@ void cRoot::LoadWorlds(cIniFile & IniFile) if (!FoundAdditionalWorlds) { - if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld") + if (a_Settings.GetKeyComment("Worlds", 0) != " World=secondworld") { - IniFile.DeleteKeyComment("Worlds", 0); - IniFile.AddKeyComment("Worlds", " World=secondworld"); + a_Settings.DeleteKeyComment("Worlds", 0); + a_Settings.AddKeyComment("Worlds", " World=secondworld"); } } } diff --git a/src/Root.h b/src/Root.h index e0b6cf26c..2b30afaff 100644 --- a/src/Root.h +++ b/src/Root.h @@ -24,6 +24,7 @@ class cWorld; class cPlayer; class cCommandOutputCallback; class cCompositeChat; +class cSettingsRepositoryInterface; typedef cItemCallback cPlayerListCallback; typedef cItemCallback cWorldListCallback; @@ -53,7 +54,7 @@ public: cRoot(void); ~cRoot(); - void Start(void); + void Start(std::unique_ptr overridesRepo); // tolua_begin cServer * GetServer(void) { return m_Server; } @@ -204,7 +205,7 @@ private: void LoadGlobalSettings(); /// Loads the worlds from settings.ini, creates the worldmap - void LoadWorlds(cIniFile & IniFile); + void LoadWorlds(cSettingsRepositoryInterface & a_Settings); /// Starts each world's life void StartWorlds(void); diff --git a/src/Server.cpp b/src/Server.cpp index 996de2695..01d5a176a 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -185,12 +185,12 @@ void cServer::PlayerDestroying(const cPlayer * a_Player) -bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) +bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth) { - m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!"); - m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100); - m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false); - m_bAllowMultiLogin = a_SettingsIni.GetValueSetB("Server", "AllowMultiLogin", false); + m_Description = a_Settings.GetValueSet("Server", "Description", "MCServer - in C++!"); + m_MaxPlayers = a_Settings.GetValueSetI("Server", "MaxPlayers", 100); + m_bIsHardcore = a_Settings.GetValueSetB("Server", "HardcoreEnabled", false); + m_bAllowMultiLogin = a_Settings.GetValueSetB("Server", "AllowMultiLogin", false); m_PlayerCount = 0; m_PlayerCountDiff = 0; @@ -205,9 +205,9 @@ bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) LOGINFO("Compatible clients: %s", MCS_CLIENT_VERSIONS); LOGINFO("Compatible protocol versions %s", MCS_PROTOCOL_VERSIONS); - m_Ports = ReadUpgradeIniPorts(a_SettingsIni, "Server", "Ports", "Port", "PortsIPv6", "25565"); + m_Ports = ReadUpgradeIniPorts(a_Settings, "Server", "Ports", "Port", "PortsIPv6", "25565"); - m_RCONServer.Initialize(a_SettingsIni); + m_RCONServer.Initialize(a_Settings); m_bIsConnected = true; @@ -226,16 +226,16 @@ bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) } // Check if both BungeeCord and online mode are on, if so, warn the admin: - m_ShouldAllowBungeeCord = a_SettingsIni.GetValueSetB("Authentication", "AllowBungeeCord", false); + m_ShouldAllowBungeeCord = a_Settings.GetValueSetB("Authentication", "AllowBungeeCord", false); if (m_ShouldAllowBungeeCord && m_ShouldAuthenticate) { LOGWARNING("WARNING: BungeeCord is allowed and server set to online mode. This is unsafe and will not work properly. Disable either authentication or BungeeCord in settings.ini."); } - m_ShouldLoadOfflinePlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadOfflinePlayerData", false); - m_ShouldLoadNamedPlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadNamedPlayerData", true); + m_ShouldLoadOfflinePlayerData = a_Settings.GetValueSetB("PlayerData", "LoadOfflinePlayerData", false); + m_ShouldLoadNamedPlayerData = a_Settings.GetValueSetB("PlayerData", "LoadNamedPlayerData", true); - m_ClientViewDistance = a_SettingsIni.GetValueSetI("Server", "DefaultViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE); + m_ClientViewDistance = a_Settings.GetValueSetI("Server", "DefaultViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE); if (m_ClientViewDistance < cClientHandle::MIN_VIEW_DISTANCE) { m_ClientViewDistance = cClientHandle::MIN_VIEW_DISTANCE; diff --git a/src/Server.h b/src/Server.h index 1f30295b7..4d0bc1c18 100644 --- a/src/Server.h +++ b/src/Server.h @@ -38,8 +38,8 @@ class cClientHandle; typedef SharedPtr cClientHandlePtr; typedef std::list cClientHandlePtrs; typedef std::list cClientHandles; -class cIniFile; class cCommandOutputCallback; +class cSettingsRepositoryInterface; namespace Json @@ -58,7 +58,7 @@ public: // tolua_end virtual ~cServer() {} - bool InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth); + bool InitServer(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth); // tolua_begin diff --git a/src/SettingsRepositoryInterface.h b/src/SettingsRepositoryInterface.h new file mode 100644 index 000000000..775a0be47 --- /dev/null +++ b/src/SettingsRepositoryInterface.h @@ -0,0 +1,46 @@ + +#pragma once + +class cSettingsRepositoryInterface +{ +public: + + enum errors + { + noID = -1, + }; + + virtual ~cSettingsRepositoryInterface() = default; + + virtual bool KeyExists(const AString keyname) const = 0; + + virtual bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const = 0; + + virtual int AddKeyName(const AString & keyname) = 0; + + virtual bool AddKeyComment(const AString & keyname, const AString & comment) = 0; + + virtual AString GetKeyComment(const AString & keyname, const int commentID) const = 0; + + virtual bool DeleteKeyComment(const AString & keyname, const int commentID) = 0; + + virtual void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) = 0; + + virtual std::vector> GetValues(AString a_keyName) = 0; + + virtual AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const = 0; + + virtual AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = "") = 0; + virtual int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0) = 0; + virtual Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0) = 0; + virtual bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) = 0; + + virtual bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true) = 0; + virtual bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true) = 0; + + + virtual bool DeleteValue(const AString & keyname, const AString & valuename) = 0; + + + virtual bool Flush() = 0; +}; diff --git a/src/main.cpp b/src/main.cpp index 1c34b8f61..d37ff0b32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Root.h" +#include "tclap/CmdLine.h" #include #include @@ -14,7 +15,7 @@ #include "OSSupport/NetworkSingleton.h" #include "BuildInfo.h" - +#include "MemorySettingsRepository.h" @@ -206,7 +207,7 @@ BOOL CtrlHandler(DWORD fdwCtrlType) //////////////////////////////////////////////////////////////////////////////// // universalMain - Main startup logic for both standard running and as a service -void universalMain() +void universalMain(std::unique_ptr overridesRepo) { #ifdef _WIN32 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) @@ -226,7 +227,7 @@ void universalMain() #endif { cRoot Root; - Root.Start(); + Root.Start(std::move(overridesRepo)); } #if !defined(ANDROID_NDK) catch (std::exception & e) @@ -363,14 +364,39 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) +std::unique_ptr parseArguments(int argc, char **argv) +{ + try + { + TCLAP::CmdLine cmd("MCServer"); + + TCLAP::ValueArg slotsArg("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); + + cmd.parse(argc, argv); + + int slots = slotsArg.getValue(); + + auto repo = make_unique(); + + repo->SetValueI("Server", "MaxPlayers", slots); + + repo->SetReadOnly(); + + return repo; + } + catch (TCLAP::ArgException &e) + { + printf("error reading command line %s for arg %s", e.error().c_str(), e.argId().c_str()); + return nullptr; + } +} + //////////////////////////////////////////////////////////////////////////////// // main: -int main( int argc, char **argv) +int main(int argc, char **argv) { - UNUSED(argc); - UNUSED(argv); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) InitLeakFinder(); @@ -425,6 +451,8 @@ int main( int argc, char **argv) // DEBUG: test the dumpfile creation: // *((int *)0) = 0; + auto argsRepo = parseArguments(argc, argv); + // Check if comm logging is to be enabled: for (int i = 0; i < argc; i++) { @@ -483,7 +511,7 @@ int main( int argc, char **argv) #endif { // Not running as a service, do normal startup - universalMain(); + universalMain(std::move(argsRepo)); } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) -- cgit v1.2.3 From c96849f431bb4152a4258d2480bef8cd272e0c6e Mon Sep 17 00:00:00 2001 From: tycho Date: Fri, 15 May 2015 13:57:27 +0100 Subject: Move make_unique into a namespace to avoid ADL issues this prevents VS finding std::make_unique for constructors that take types from std --- src/Globals.h | 10 +++++++--- src/Root.cpp | 4 ++-- src/World.cpp | 10 +++++----- src/main.cpp | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Globals.h b/src/Globals.h index cee2094bc..27d944fcc 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -433,10 +433,14 @@ typename std::enable_if::value, C>::type CeilC(T a_Value) //temporary replacement for std::make_unique until we get c++14 -template -std::unique_ptr make_unique(Args&&... args) + +namespace cpp14 { - return std::unique_ptr(new T(std::forward(args)...)); + template + std::unique_ptr make_unique(Args&&... args) + { + return std::unique_ptr(new T(std::forward(args)...)); + } } // a tick is 50 ms diff --git a/src/Root.cpp b/src/Root.cpp index de53e0cd8..c3c880e73 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -133,7 +133,7 @@ void cRoot::Start(std::unique_ptr overridesRepo) LOG("Reading server config..."); - auto IniFile = make_unique(); + auto IniFile = cpp14::make_unique(); if (!IniFile->ReadFile("settings.ini")) { LOGWARN("Regenerating settings.ini, all settings will be reset"); @@ -141,7 +141,7 @@ void cRoot::Start(std::unique_ptr overridesRepo) IniFile->AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini"); IniFile->AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help"); } - auto settingsRepo = make_unique(std::move(IniFile), std::move(overridesRepo)); + auto settingsRepo = cpp14::make_unique(std::move(IniFile), std::move(overridesRepo)); LOG("Starting server..."); m_MojangAPI = new cMojangAPI; diff --git a/src/World.cpp b/src/World.cpp index c0a79b9d0..eb8835467 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -621,18 +621,18 @@ void cWorld::Start(void) InitialiseAndLoadMobSpawningValues(IniFile); SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", GetTimeOfDay())); - m_ChunkMap = make_unique(this); + m_ChunkMap = cpp14::make_unique(this); // preallocate some memory for ticking blocks so we don't need to allocate that often m_BlockTickQueue.reserve(1000); m_BlockTickQueueCopy.reserve(1000); // Simulators: - m_SimulatorManager = make_unique(*this); + m_SimulatorManager = cpp14::make_unique(*this); m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); - m_SandSimulator = make_unique(*this, IniFile); - m_FireSimulator = make_unique(*this, IniFile); + m_SandSimulator = cpp14::make_unique(*this, IniFile); + m_FireSimulator = cpp14::make_unique(*this, IniFile); m_RedstoneSimulator = InitializeRedstoneSimulator(IniFile); // Water, Lava and Redstone simulators get registered in their initialize function. @@ -2680,7 +2680,7 @@ void cWorld::UnloadUnusedChunks(void) void cWorld::QueueUnloadUnusedChunks(void) { - QueueTask(make_unique()); + QueueTask(cpp14::make_unique()); } diff --git a/src/main.cpp b/src/main.cpp index d37ff0b32..9f57ad6bd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -376,7 +376,7 @@ std::unique_ptr parseArguments(int argc, char **argv) int slots = slotsArg.getValue(); - auto repo = make_unique(); + auto repo = cpp14::make_unique(); repo->SetValueI("Server", "MaxPlayers", slots); -- cgit v1.2.3 From 0da8c7392e753b89b20dc0678e78ab3060e535ed Mon Sep 17 00:00:00 2001 From: worktycho Date: Fri, 15 May 2015 14:54:48 +0100 Subject: Fix service Main --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 9f57ad6bd..a0f51105a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -258,7 +258,7 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam) UNREFERENCED_PARAMETER(lpParam); // Do the normal startup - universalMain(); + universalMain(cpp14::make_unique()); return ERROR_SUCCESS; } -- cgit v1.2.3 From 36fe8ee5f5ef9ed3641be34311d9d0a2259afd68 Mon Sep 17 00:00:00 2001 From: tycho Date: Sat, 16 May 2015 12:46:43 +0100 Subject: Added deoxy comments --- src/SettingsRepositoryInterface.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/SettingsRepositoryInterface.h b/src/SettingsRepositoryInterface.h index 775a0be47..443b90ff5 100644 --- a/src/SettingsRepositoryInterface.h +++ b/src/SettingsRepositoryInterface.h @@ -12,35 +12,50 @@ public: virtual ~cSettingsRepositoryInterface() = default; + /** Returns true iff the specified key exists */ virtual bool KeyExists(const AString keyname) const = 0; + /** Returns true iff the specified value exists. */ virtual bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const = 0; + /** Add a key name. Return value is not required to mean anything **/ virtual int AddKeyName(const AString & keyname) = 0; + /** Add a key comment, will always fail if the repository does not support comments **/ virtual bool AddKeyComment(const AString & keyname, const AString & comment) = 0; + /** Return a key comment, returns "" for repositories that do not return comments **/ virtual AString GetKeyComment(const AString & keyname, const int commentID) const = 0; + /** Delete a key comment, will always fail if the repository does not support comments **/ virtual bool DeleteKeyComment(const AString & keyname, const int commentID) = 0; + /** Adds a new value to the specified key. + If a value of the same name already exists, creates another one **/ virtual void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) = 0; + /** returns a vector containing a name, value pair for each value under the key **/ virtual std::vector> GetValues(AString a_keyName) = 0; + /** Get the value at the specified key and value, returns defValue on failure **/ virtual AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const = 0; + /** Gets the value; if not found, write the default to the repository **/ virtual AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = "") = 0; virtual int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0) = 0; virtual Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0) = 0; virtual bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) = 0; + /** Overwrites the value of the key, value pair + Specify the optional parameter as false if you do not want the value created if it doesn't exist. + Returns true if value set, false otherwise. **/ virtual bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true) = 0; virtual bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true) = 0; - + /** Deletes the specified key, value pair **/ virtual bool DeleteValue(const AString & keyname, const AString & valuename) = 0; + /** Writes the changes to the backing store, if the repository has one **/ virtual bool Flush() = 0; }; -- cgit v1.2.3 From aedf9d05cb798e2ed3f9666028d12753929504fc Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 18 May 2015 13:32:47 +0100 Subject: Improved leaves a bit more. Should fix #2058. --- src/Blocks/BlockLeaves.h | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 8e44c94ac..4d4610fd8 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -40,29 +40,41 @@ public: { cFastRandom rand; - // Old leaves - 3 bits contain display; new leaves - 1st bit, shifted left two for saplings to understand - if (rand.NextInt(20) == 0) + // There is a chance to drop a sapling that varies depending on the type of leaf broken. + // TODO: Take into account fortune for sapling drops. + int chance; + if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_JUNGLE)) + { + // Jungle leaves have a 2.5% chance of dropping a sapling. + chance = rand.NextInt(40); + } + else + { + // Other leaves have a 5% chance of dropping a sapling. + chance = rand.NextInt(20); + } + if (chance == 0) { a_Pickups.push_back( cItem( E_BLOCK_SAPLING, 1, - (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : (2 << (a_BlockMeta & 0x01)) + (m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : (4 + (a_BlockMeta & 0x01)) ) ); } - - // 1 % chance of dropping an apple, if the leaves' type is Apple Leaves + + // 0.5 % chance of dropping an apple, if the leaves' type is Apple Leaves if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_APPLE)) { - if (rand.NextInt(101) == 0) + if (rand.NextInt(200) == 0) { a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); } } } - - + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); -- cgit v1.2.3 From c2303ac4cf072f8e273ba9ddf72f5ef88c4baf13 Mon Sep 17 00:00:00 2001 From: tycho Date: Mon, 18 May 2015 15:43:26 +0100 Subject: Fix max slots logic to only override if acctually present. --- src/main.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a0f51105a..2cf4b383e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -373,12 +373,17 @@ std::unique_ptr parseArguments(int argc, char **argv) TCLAP::ValueArg slotsArg("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); cmd.parse(argc, argv); - - int slots = slotsArg.getValue(); auto repo = cpp14::make_unique(); - repo->SetValueI("Server", "MaxPlayers", slots); + if (slotsArg.isSet()) + { + + int slots = slotsArg.getValue(); + + repo->SetValueI("Server", "MaxPlayers", slots); + + } repo->SetReadOnly(); @@ -387,7 +392,7 @@ std::unique_ptr parseArguments(int argc, char **argv) catch (TCLAP::ArgException &e) { printf("error reading command line %s for arg %s", e.error().c_str(), e.argId().c_str()); - return nullptr; + return cpp14::make_unique(); } } -- cgit v1.2.3 From 2e98bfc4e98c1cb0730514628d501c2ca0326c4e Mon Sep 17 00:00:00 2001 From: tycho Date: Mon, 18 May 2015 16:04:27 +0100 Subject: Add support for setting ports through command line --- src/IniFile.cpp | 13 ++++++++++++- src/main.cpp | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/IniFile.cpp b/src/IniFile.cpp index 8dab87d15..cd98cce57 100644 --- a/src/IniFile.cpp +++ b/src/IniFile.cpp @@ -931,7 +931,18 @@ AStringVector ReadUpgradeIniPorts( ) { // Read the regular value, but don't use the default (in order to detect missing value for upgrade): - AStringVector Ports = StringSplitAndTrim(a_Settings.GetValue(a_KeyName, a_PortsValueName), ";,"); + + AStringVector Ports; + + for (auto pair : a_Settings.GetValues(a_KeyName)) + { + if (pair.first != a_PortsValueName) + { + continue; + } + AStringVector temp = StringSplitAndTrim(pair.second, ";,"); + Ports.insert(Ports.end(), temp.begin(), temp.end()); + } if (Ports.empty()) { diff --git a/src/main.cpp b/src/main.cpp index 2cf4b383e..8a237b8ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -372,6 +372,8 @@ std::unique_ptr parseArguments(int argc, char **argv) TCLAP::ValueArg slotsArg("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); + TCLAP::MultiArg portsArg("p", "port", "The port number the server should listen to", false, "port", cmd); + cmd.parse(argc, argv); auto repo = cpp14::make_unique(); @@ -381,8 +383,17 @@ std::unique_ptr parseArguments(int argc, char **argv) int slots = slotsArg.getValue(); - repo->SetValueI("Server", "MaxPlayers", slots); + repo->AddValue("Server", "MaxPlayers", static_cast(slots)); + + } + if (portsArg.isSet()) + { + std::vector ports = portsArg.getValue(); + for (auto port : ports) + { + repo->AddValue("Server", "Port", static_cast(port)); + } } repo->SetReadOnly(); -- cgit v1.2.3 From 4d4d1e9c69a15e154bc358f1363b961de80b27d6 Mon Sep 17 00:00:00 2001 From: Lukas Pioch Date: Mon, 18 May 2015 22:29:39 +0200 Subject: Added hooks HOOK_ENTITY_CHANGE_WORLD and HOOK_ENTITY_CHANGED_WORLD Fixes #1435. --- src/Bindings/Plugin.h | 2 ++ src/Bindings/PluginLua.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++ src/Bindings/PluginLua.h | 2 ++ src/Bindings/PluginManager.cpp | 36 ++++++++++++++++++++++++++++++ src/Bindings/PluginManager.h | 4 ++++ src/Entities/Entity.cpp | 11 ++++++++++ src/Entities/Player.cpp | 10 +++++++++ 7 files changed, 115 insertions(+) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index d0c2bcefa..b4bbfd802 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -56,6 +56,8 @@ public: virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) = 0; virtual bool OnEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; + virtual bool OnEntityChangeWorld (cEntity & a_Entity, cWorld & a_World) = 0; + virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) = 0; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) = 0; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 76d3557a4..a8be26f71 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -534,6 +534,54 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E +bool cPluginLua::OnEntityChangeWorld(cEntity & a_Entity, cWorld & a_World) +{ + cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGE_WORLD]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Entity, &a_World, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World) +{ + cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGED_WORLD]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Entity, &a_World, res); + if (res) + { + return true; + } + } + return false; +} + + + + + bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) { cCSLock Lock(m_CriticalSection); @@ -1884,6 +1932,8 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_DISCONNECT: return "OnDisconnect"; case cPluginManager::HOOK_PLAYER_ANIMATION: return "OnPlayerAnimation"; case cPluginManager::HOOK_ENTITY_ADD_EFFECT: return "OnEntityAddEffect"; + case cPluginManager::HOOK_ENTITY_CHANGE_WORLD: return "OnEntityChangeWorld"; + case cPluginManager::HOOK_ENTITY_CHANGED_WORLD: return "OnEntityChangedWorld"; case cPluginManager::HOOK_ENTITY_TELEPORT: return "OnEntityTeleport"; case cPluginManager::HOOK_EXECUTE_COMMAND: return "OnExecuteCommand"; case cPluginManager::HOOK_HANDSHAKE: return "OnHandshake"; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 524c249b0..533dc0331 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -115,6 +115,8 @@ public: virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override; virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) override; + virtual bool OnEntityChangeWorld (cEntity & a_Entity, cWorld & a_World) override; + virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) override; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) override; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index db2493955..cc74c8372 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -525,6 +525,42 @@ bool cPluginManager::CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & +bool cPluginManager::CallHookEntityChangeWorld(cEntity & a_Entity, cWorld & a_World) +{ + FIND_HOOK(HOOK_ENTITY_CHANGE_WORLD); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnEntityChangeWorld(a_Entity, a_World)) + { + return true; + } + } + return false; +} + + + + +bool cPluginManager::CallHookEntityChangedWorld(cEntity & a_Entity, cWorld & a_World) +{ + FIND_HOOK(HOOK_ENTITY_CHANGED_WORLD); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnEntityChangedWorld(a_Entity, a_World)) + { + return true; + } + } + return false; +} + + + + bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result) { FIND_HOOK(HOOK_EXECUTE_COMMAND); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index d8c886b62..2c3eaa75f 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -85,6 +85,8 @@ public: HOOK_DISCONNECT, HOOK_PLAYER_ANIMATION, HOOK_ENTITY_ADD_EFFECT, + HOOK_ENTITY_CHANGE_WORLD, + HOOK_ENTITY_CHANGED_WORLD, HOOK_EXECUTE_COMMAND, HOOK_EXPLODED, HOOK_EXPLODING, @@ -200,6 +202,8 @@ public: bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason); bool CallHookEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier); bool CallHookEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition); + bool CallHookEntityChangeWorld (cEntity & a_Entity, cWorld & a_World); + bool CallHookEntityChangedWorld (cEntity & a_Entity, cWorld & a_World); bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result); // If a_Player == nullptr, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4a909a1fd..bc2b3e93e 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1403,14 +1403,25 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) return false; } + // Ask the plugins if the entity is allowed to change the world + if (cRoot::Get()->GetPluginManager()->CallHookEntityChangeWorld(*this, *a_World)) + { + // A Plugin doesn't allow the entity to change the world + return false; + } + // Remove all links to the old world SetWorldTravellingFrom(GetWorld()); // cChunk::Tick() handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world a_World->AddEntity(this); + cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD SetWorld(a_World); + // Entity changed the world, call the hook + cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld); + return true; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 607a663de..01ad26297 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1606,6 +1606,12 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) return false; } + if (cRoot::Get()->GetPluginManager()->CallHookEntityChangeWorld(*this, *a_World)) + { + // A Plugin doesn't allow the player to change the world + return false; + } + // Send the respawn packet: if (a_ShouldSendRespawn && (m_ClientHandle != nullptr)) { @@ -1621,6 +1627,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) // Queue adding player to the new world, including all the necessary adjustments to the object a_World->AddPlayer(this); + cWorld * OldWorld = cRoot::Get()->GetWorld(GetWorld()->GetName()); // Required for the hook HOOK_ENTITY_CHANGED_WORLD SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value // Update the view distance. @@ -1635,6 +1642,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) // Broadcast the player into the new world. a_World->BroadcastSpawnEntity(*this); + // Player changed the world, call the hook + cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld); + return true; } -- cgit v1.2.3 From 9aced8cd856eb66b7ff136cc77bca32cb4901354 Mon Sep 17 00:00:00 2001 From: Lukas Pioch Date: Tue, 19 May 2015 06:34:40 +0200 Subject: Added OnEntityChangeWorld.lua and OnEntityChangedWorld.lua hooks to APIDump --- .../Plugins/APIDump/Hooks/OnEntityChangeWorld.lua | 29 ++++++++++++++++++++++ .../Plugins/APIDump/Hooks/OnEntityChangedWorld.lua | 28 +++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua create mode 100644 MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua diff --git a/MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua b/MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua new file mode 100644 index 000000000..25072ca5c --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua @@ -0,0 +1,29 @@ +return +{ + HOOK_ENTITY_CHANGE_WORLD = + { + CalledWhen = "Before a entity is changing the world.", + DefaultFnName = "OnEntityChangeWorld", -- also used as pagename + Desc = [[ + This hook is called before the server moves the {{cEntity|entity}} to the given world. Plugins may + refuse the changing of the entity to the new world.

+ See also the {{OnEntityChangedWorld|HOOK_ENTITY_CHANGED_WORLD}} hook for a similar hook is called after the + entity has been moved to the world. + ]], + Params = + { + { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity that wants to change the world" }, + { Name = "World", Type = "{{cWorld}}", Notes = "The world to which the entity wants to change" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event and the change of the entity to the world is + cancelled. + ]], + }, -- HOOK_ENTITY_CHANGE_WORLD +} + + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua b/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua new file mode 100644 index 000000000..00645c152 --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua @@ -0,0 +1,28 @@ +return +{ + HOOK_ENTITY_CHANGED_WORLD = + { + CalledWhen = "After a entity has changed the world.", + DefaultFnName = "OnEntityChangedWorld", -- also used as pagename + Desc = [[ + This hook is called after the server has moved the {{cEntity|entity}} to the given world. This is an information-only + callback, the entity is already in the new world.

+ See also the {{OnEntityChangeWorld|HOOK_ENTITY_CHANGE_WORLD}} hook for a similar hook called before the + entity is moved to the new world. + ]], + Params = + { + { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity that has changed the world" }, + { Name = "World", Type = "{{cWorld}}", Notes = "The world from which the entity has come" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called. If the function + returns true, no other callback is called for this event. + ]], + }, -- HOOK_ENTITY_CHANGED_WORLD +} + + + + + -- cgit v1.2.3 From d1a0717a57a84dde634db57092120eb78f961751 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 19 May 2015 09:27:14 +0100 Subject: Improved contributor --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a25c6f06b..21654428f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -7,6 +7,7 @@ Diusrex Duralex FakeTruth (founder) Howaner +jasperarmstrong keyboard Lapayo Luksor -- cgit v1.2.3 From d852209f8db9129a3d135a4f7034878d1438a57b Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 19 May 2015 09:29:27 +0100 Subject: Manual merge of #2066 --- src/Mobs/Monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index a29d67d15..2b00f6959 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -519,7 +519,7 @@ void cMonster::SetPitchAndYawFromDestination() double HeadRotation, HeadPitch; Distance.Normalize(); VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); - if (abs(BodyRotation - HeadRotation) < 120) + if (std::abs(BodyRotation - HeadRotation) < 120) { SetHeadYaw(HeadRotation); SetPitch(-HeadPitch); -- cgit v1.2.3 From e7d948dc3c961e5e5ccd89217ff5709a37ba2ef6 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 19 May 2015 09:38:37 +0100 Subject: Removed tip4commit, it's not used anymore. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 3d013eff5..43ec942d5 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,7 @@ Check out the [CONTRIBUTING.md](https://github.com/mc-server/MCServer/blob/maste Other Stuff ----------- -For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [Plugin API](http://mc-server.xoft.cz/LuaAPI/). - -Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) +For other stuff, including plugins and discussion, check out the [forums](http://forum.mc-server.org) and [Plugin API](http://mc-server.xoft.cz/LuaAPI/). Support Us on Gratipay: [![Support via Gratipay](http://img.shields.io/gittip/cuberite_team.svg)](https://www.gratipay.com/cuberite_team) -- cgit v1.2.3