From 40e15c5ad517a6f860b39d1b225596424c3d2506 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 5 Aug 2014 18:37:00 +0200 Subject: [PATCH 001/102] RankMgr: Initial interface declaration. --- src/CMakeLists.txt | 2 + src/RankManager.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++ src/RankManager.h | 103 +++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 src/RankManager.cpp create mode 100644 src/RankManager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db9c61082..d6066b38b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,7 @@ SET (SRCS MonsterConfig.cpp Noise.cpp ProbabDistrib.cpp + RankManager.cpp RCONServer.cpp Root.cpp Scoreboard.cpp @@ -121,6 +122,7 @@ SET (HDRS MonsterConfig.h Noise.h ProbabDistrib.h + RankManager.h RCONServer.h Root.h Scoreboard.h diff --git a/src/RankManager.cpp b/src/RankManager.cpp new file mode 100644 index 000000000..954edd099 --- /dev/null +++ b/src/RankManager.cpp @@ -0,0 +1,153 @@ + +// RankManager.cpp + +// Implements the cRankManager class that represents the rank manager responsible for assigning permissions and message visuals to players + +#include "Globals.h" +#include "RankManager.h" +#include "Protocol/MojangAPI.h" +#include "inifile/iniFile.h" +#include + + + + + +/* +// This code is for internal testing while developing the cRankManager class +static class cRankMgrTest +{ +public: + cRankMgrTest(void) : + m_Mgr() + { + // Initialize the cMojangAPI so that it can convert playernames to UUIDs: + cIniFile Ini; + Ini.ReadFile("settings.ini"); + m_API.Start(Ini); + + // Test the cRankManager class: + ReportPlayer("xoft"); + } + + void ReportPlayer(const AString & a_PlayerName) + { + // Get the player's UUID and rank: + AString UUID = m_API.GetUUIDFromPlayerName(a_PlayerName); + std::cout << "Player " << a_PlayerName << " has UUID '" << UUID <<"'." << std::endl; + std::cout << " Rank: '" << m_Mgr.GetPlayerRankName(UUID) << "'." << std::endl; + + // List all the permission groups for the player: + AStringVector Groups = m_Mgr.GetPlayerPermissionGroups(UUID); + std::cout << " Groups(" << Groups.size() << "):" << std::endl; + for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) + { + std::cout << " '" << *itr << "'." << std::endl; + } // for itr - Groups[] + + // List all the permissions for the player: + AStringVector Permissions = m_Mgr.GetPlayerPermissions(UUID); + std::cout << " Permissions(" << Permissions.size() << "):" << std::endl; + for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) + { + std::cout << " '" << *itr << "'." << std::endl; + } // for itr - Groups[] + + std::cout << "Done." << std::endl; + } + +protected: + cRankManager m_Mgr; + cMojangAPI m_API; +} g_RankMgrTest; +//*/ + + + + + +cRankManager::cRankManager(void) : + m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) +{ + // Create the DB tables, if they don't exist: + m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID, Name, MsgPrefix, MsgPostfix, MsgNameColorCode)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionGroup (GroupID, Name)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermissionGroups (RankID, GroupID)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (GroupID, Permission)"); + + // TODO: Check if tables empty, add some defaults then +} + + + + + +AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) +{ + SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?"); + stmt.bind(1, a_PlayerUUID); + stmt.executeStep(); + if (stmt.isDone()) + { + // No data returned from the DB + return AString(); + } + return stmt.getColumn(0).getText(); +} + + + + + +AStringVector cRankManager::GetPlayerPermissionGroups(const AString & a_PlayerUUID) +{ + // Prepare the DB statement: + SQLite::Statement stmt(m_DB, + "SELECT PermissionGroup.Name FROM PermissionGroup " + "LEFT JOIN RankPermissionGroups " + "ON PermissionGroup.GroupID = RankPermissionGroups.GroupID " + "LEFT JOIN PlayerRank " + "ON PlayerRank.RankID = RankPermissionGroups.RankID " + "WHERE PlayerRank.PlayerUUID = ?" + ); + stmt.bind(1, a_PlayerUUID); + + // Execute and get results: + AStringVector res; + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + return res; +} + + + + + +AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) +{ + // Prepare the DB statement: + SQLite::Statement stmt(m_DB, + "SELECT PermissionItem.Permission FROM PermissionItem " + "LEFT JOIN RankPermissionGroups " + "ON PermissionItem.GroupID = RankPermissionGroups.GroupID " + "LEFT JOIN PlayerRank " + "ON PlayerRank.RankID = RankPermissionGroups.RankID " + "WHERE PlayerRank.PlayerUUID = ?" + ); + stmt.bind(1, a_PlayerUUID); + + // Execute and get results: + AStringVector res; + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + return res; +} + + + + diff --git a/src/RankManager.h b/src/RankManager.h new file mode 100644 index 000000000..cda6beee9 --- /dev/null +++ b/src/RankManager.h @@ -0,0 +1,103 @@ + +// RankManager.h + +// Declares the cRankManager class that represents the rank manager responsible for assigning permissions and message visuals to players + + + + +#pragma once + +#include "SQLiteCpp/Database.h" + + + + + +class cRankManager +{ +public: + cRankManager(void); + + /** Returns the name of the rank that the specified player has assigned to them. */ + AString GetPlayerRankName(const AString & a_PlayerUUID); + + /** Returns the names of PermissionGroups that the specified player has assigned to them. */ + AStringVector GetPlayerPermissionGroups(const AString & a_PlayerUUID); + + /** Returns the permissions that the specified player has assigned to them. */ + AStringVector GetPlayerPermissions(const AString & a_PlayerUUID); + + /** Returns the names of groups that the specified rank has assigned to it. */ + AStringVector GetRankPermissionGroups(const AString & a_RankName); + + /** Returns the permissions that the specified permission group has assigned to it. */ + AStringVector GetPermissionGroupPermissiont(const AString & a_GroupName); + + /** Returns the names of all defined ranks. */ + AStringVector GetAllRanks(void); + + /** Returns the names of all permission groups. */ + AStringVector GetAllPermissionGroups(void); + + /** Returns all the distinct permissions that are stored in the DB. */ + AStringVector GetAllPermissions(void); + + /** Returns the message visuals (prefix, postfix, color) for the specified player. */ + void GetPlayerMsgVisuals( + const AString & a_PlayerUUID, + AString & a_MsgPrefix, + AString & a_MsgPostfix, + AString & a_MsgNameColorCode + ); + + /** Adds a new rank. No action if the rank already exists. */ + void AddRank(const AString & a_RankName); + + /** Adds a new permission group. No action if such a group already exists. */ + void AddPermissionGroup(const AString & a_GroupName); + + /** Adds the specified permission group to the specified rank. + Fails if the rank or group names are not found. + Returns true if successful, false on error. */ + bool AddPermissionGroupToRank(const AString & a_RankName, const AString & a_GroupName); + + /** Adds the specified permission to the specified permission group. + Fails if the permission group name is not found. + Returns true if successful, false on error. */ + bool AddPermissionToPermissionGroup(const AString & a_Permission, const AString & a_GroupName); + + /** Removes the specified rank. + All players assigned to that rank will be re-assigned to a_ReplacementRankName, unless it is empty. */ + void RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName); + + /** Removes the specified permission group. */ + void RemovePermissionGroup(const AString & a_PermissionGroup); + + /** Removes the specified permission from the specified permission group. */ + void RemovePermission(const AString & a_Permission, const AString & a_PermissionGroup); + + /** Renames the specified rank. No action if the rank name is not found. + Fails if the new name is already used. + Returns true on success, false on failure. */ + bool RenameRank(const AString & a_OldName, const AString & a_NewName); + + /** Renames the specified permission group. No action if the rank name is not found. + Fails if the new name is already used. + Returns true on success, false on failure. */ + bool RenamePermissionGroup(const AString & a_OldName, const AString & a_NewName); + + /** Sets the specified player's rank. + If the player already had rank assigned to them, it is overwritten with the new rank. + Note that this doesn't change the cPlayer if the player is already connected, you need to update all the + cPlayer instances manually. */ + void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_RankName); + +protected: + + SQLite::Database m_DB; +} ; + + + + From fcfae0252503a845c98fe6e882dda69e44224094 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 5 Aug 2014 22:28:37 +0200 Subject: [PATCH 002/102] RankMgr: More interface. --- src/RankManager.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/RankManager.h b/src/RankManager.h index cda6beee9..1eaeb97a1 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -47,12 +47,17 @@ public: void GetPlayerMsgVisuals( const AString & a_PlayerUUID, AString & a_MsgPrefix, - AString & a_MsgPostfix, + AString & a_MsgSuffix, AString & a_MsgNameColorCode ); /** Adds a new rank. No action if the rank already exists. */ - void AddRank(const AString & a_RankName); + void AddRank( + const AString & a_RankName, + const AString & a_MsgPrefix, + const AString & a_MsgSuffix, + const AString & a_MsgNameColorCode + ); /** Adds a new permission group. No action if such a group already exists. */ void AddPermissionGroup(const AString & a_GroupName); @@ -93,6 +98,13 @@ public: cPlayer instances manually. */ void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_RankName); + /** Sets the message visuals of an existing rank. No action if the rank name is not found. */ + void SetRankVisuals( + const AString & a_RankName, + const AString & a_MsgPrefix, + const AString & a_MsgSuffix, + const AString & a_MsgNameColorCode + ); protected: SQLite::Database m_DB; From a717a7e712e6be1e6980cade95f09b5b85bdfe67 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 5 Aug 2014 22:32:26 +0200 Subject: [PATCH 003/102] RankMgr: Added SQL integer datatypes. --- src/RankManager.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 954edd099..18ed65b26 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -70,11 +70,11 @@ cRankManager::cRankManager(void) : m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) { // Create the DB tables, if they don't exist: - m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID, Name, MsgPrefix, MsgPostfix, MsgNameColorCode)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionGroup (GroupID, Name)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermissionGroups (RankID, GroupID)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (GroupID, Permission)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgPostfix, MsgNameColorCode)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionGroup (GroupID INTEGER PRIMARY KEY, Name)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermissionGroups (RankID INTEGER, GroupID INTEGER)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (GroupID INTEGER, Permission)"); // TODO: Check if tables empty, add some defaults then } From 670e94bfeb62a51ca64ffaa0e45086e1ca91057c Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 09:56:28 +0200 Subject: [PATCH 004/102] RankMgr: Renamed PermissionGroup to Group in API and PermGroup in DB. "Group" is SQL keyword and shouldn't be used as table name. --- src/RankManager.cpp | 26 +++++++++++++------------- src/RankManager.h | 38 +++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 18ed65b26..e77fb22b9 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -13,7 +13,7 @@ -/* +//* // This code is for internal testing while developing the cRankManager class static class cRankMgrTest { @@ -38,7 +38,7 @@ public: std::cout << " Rank: '" << m_Mgr.GetPlayerRankName(UUID) << "'." << std::endl; // List all the permission groups for the player: - AStringVector Groups = m_Mgr.GetPlayerPermissionGroups(UUID); + AStringVector Groups = m_Mgr.GetPlayerGroups(UUID); std::cout << " Groups(" << Groups.size() << "):" << std::endl; for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) { @@ -72,9 +72,9 @@ cRankManager::cRankManager(void) : // Create the DB tables, if they don't exist: m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgPostfix, MsgNameColorCode)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionGroup (GroupID INTEGER PRIMARY KEY, Name)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermissionGroups (RankID INTEGER, GroupID INTEGER)"); - m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (GroupID INTEGER, Permission)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermGroup (PermGroupID INTEGER PRIMARY KEY, Name)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (PermGroupID INTEGER, Permission)"); // TODO: Check if tables empty, add some defaults then } @@ -100,15 +100,15 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) -AStringVector cRankManager::GetPlayerPermissionGroups(const AString & a_PlayerUUID) +AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) { // Prepare the DB statement: SQLite::Statement stmt(m_DB, - "SELECT PermissionGroup.Name FROM PermissionGroup " - "LEFT JOIN RankPermissionGroups " - "ON PermissionGroup.GroupID = RankPermissionGroups.GroupID " + "SELECT Group.Name FROM Group " + "LEFT JOIN RankGroups " + "ON Group.GroupID = RankGroups.GroupID " "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankPermissionGroups.RankID " + "ON PlayerRank.RankID = RankGroups.RankID " "WHERE PlayerRank.PlayerUUID = ?" ); stmt.bind(1, a_PlayerUUID); @@ -131,10 +131,10 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) // Prepare the DB statement: SQLite::Statement stmt(m_DB, "SELECT PermissionItem.Permission FROM PermissionItem " - "LEFT JOIN RankPermissionGroups " - "ON PermissionItem.GroupID = RankPermissionGroups.GroupID " + "LEFT JOIN RankGroups " + "ON PermissionItem.GroupID = RankGroups.GroupID " "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankPermissionGroups.RankID " + "ON PlayerRank.RankID = RankGroups.RankID " "WHERE PlayerRank.PlayerUUID = ?" ); stmt.bind(1, a_PlayerUUID); diff --git a/src/RankManager.h b/src/RankManager.h index 1eaeb97a1..0b1db2fb8 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -22,23 +22,26 @@ public: /** Returns the name of the rank that the specified player has assigned to them. */ AString GetPlayerRankName(const AString & a_PlayerUUID); - /** Returns the names of PermissionGroups that the specified player has assigned to them. */ - AStringVector GetPlayerPermissionGroups(const AString & a_PlayerUUID); + /** Returns the names of Groups that the specified player has assigned to them. */ + AStringVector GetPlayerGroups(const AString & a_PlayerUUID); /** Returns the permissions that the specified player has assigned to them. */ AStringVector GetPlayerPermissions(const AString & a_PlayerUUID); /** Returns the names of groups that the specified rank has assigned to it. */ - AStringVector GetRankPermissionGroups(const AString & a_RankName); + AStringVector GetRankGroups(const AString & a_RankName); - /** Returns the permissions that the specified permission group has assigned to it. */ - AStringVector GetPermissionGroupPermissiont(const AString & a_GroupName); + /** Returns the permissions that the specified group has assigned to it. */ + AStringVector GetGroupPermissions(const AString & a_GroupName); + + /** Returns all permissions that the specified rank has assigned to it, through all its groups. */ + AStringVector GetRankPermissions(const AString & a_RankName); /** Returns the names of all defined ranks. */ AStringVector GetAllRanks(void); /** Returns the names of all permission groups. */ - AStringVector GetAllPermissionGroups(void); + AStringVector GetAllGroups(void); /** Returns all the distinct permissions that are stored in the DB. */ AStringVector GetAllPermissions(void); @@ -60,37 +63,42 @@ public: ); /** Adds a new permission group. No action if such a group already exists. */ - void AddPermissionGroup(const AString & a_GroupName); + void AddGroup(const AString & a_GroupName); /** Adds the specified permission group to the specified rank. Fails if the rank or group names are not found. Returns true if successful, false on error. */ - bool AddPermissionGroupToRank(const AString & a_RankName, const AString & a_GroupName); + bool AddGroupToRank(const AString & a_RankName, const AString & a_GroupName); /** Adds the specified permission to the specified permission group. Fails if the permission group name is not found. Returns true if successful, false on error. */ - bool AddPermissionToPermissionGroup(const AString & a_Permission, const AString & a_GroupName); + bool AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName); /** Removes the specified rank. All players assigned to that rank will be re-assigned to a_ReplacementRankName, unless it is empty. */ void RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName); - /** Removes the specified permission group. */ - void RemovePermissionGroup(const AString & a_PermissionGroup); + /** Removes the specified group completely. + The group will first be removed from all ranks using it, and then removed itself. */ + void RemoveGroup(const AString & a_GroupName); - /** Removes the specified permission from the specified permission group. */ - void RemovePermission(const AString & a_Permission, const AString & a_PermissionGroup); + /** Removes the specified group from the specified rank. + The group will stay defined, even if no rank is using it. */ + void RemoveGroupFromRank(const AString & a_RankName, const AString & a_GroupName); + + /** Removes the specified permission from the specified group. */ + void RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName); /** Renames the specified rank. No action if the rank name is not found. Fails if the new name is already used. Returns true on success, false on failure. */ bool RenameRank(const AString & a_OldName, const AString & a_NewName); - /** Renames the specified permission group. No action if the rank name is not found. + /** Renames the specified group. No action if the rank name is not found. Fails if the new name is already used. Returns true on success, false on failure. */ - bool RenamePermissionGroup(const AString & a_OldName, const AString & a_NewName); + bool RenameGroup(const AString & a_OldName, const AString & a_NewName); /** Sets the specified player's rank. If the player already had rank assigned to them, it is overwritten with the new rank. From 65b81b4ab7f580c98ca80b8e57a13de961f19131 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 10:02:25 +0200 Subject: [PATCH 005/102] RankMgr: Implemented the basic API functions. --- src/RankManager.cpp | 738 ++++++++++++++++++++++++++++++++++++++++---- src/RankManager.h | 18 +- 2 files changed, 696 insertions(+), 60 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index e77fb22b9..e02e63a24 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -5,15 +5,13 @@ #include "Globals.h" #include "RankManager.h" -#include "Protocol/MojangAPI.h" -#include "inifile/iniFile.h" -#include +#include "SQLiteCpp/Transaction.h" -//* +/* // This code is for internal testing while developing the cRankManager class static class cRankMgrTest { @@ -21,44 +19,72 @@ public: cRankMgrTest(void) : m_Mgr() { - // Initialize the cMojangAPI so that it can convert playernames to UUIDs: - cIniFile Ini; - Ini.ReadFile("settings.ini"); - m_API.Start(Ini); + // Initialize logging: + new cMCLogger(); + AString UUID = "b1caf24202a841a78055a079c460eee7"; // UUID for "xoft" + LOG("Testing UUID %s", UUID.c_str()); - // Test the cRankManager class: - ReportPlayer("xoft"); + // Test the initial state of the ranks: + LOG("Initial test:"); + ReportPlayer(UUID); + + // Add a rank, a few groups and permissions and set the player to use them: + LOG("Adding data..."); + m_Mgr.AddRank("TestRank", "[test]", "[/test]", "7"); + m_Mgr.AddGroup("TestGroup1"); + m_Mgr.AddGroup("TestGroup2"); + m_Mgr.AddGroupToRank("TestGroup1", "TestRank"); + m_Mgr.AddGroupToRank("TestGroup2", "TestRank"); + m_Mgr.AddPermissionToGroup("testpermission1.1", "TestGroup1"); + m_Mgr.AddPermissionToGroup("testpermission1.2", "TestGroup1"); + m_Mgr.AddPermissionToGroup("testpermission2.1", "TestGroup2"); + m_Mgr.SetPlayerRank(UUID, "TestRank"); + + // Test the added data: + LOG("Testing the added data:"); + LOG("IsGroupInRank(TestGroup1, TestRank) = %s", m_Mgr.IsGroupInRank("TestGroup1", "TestRank") ? "true" : "false"); + LOG("IsGroupInRank(TestGroup3, TestRank) = %s", m_Mgr.IsGroupInRank("TestGroup3", "TestRank") ? "true" : "false"); + LOG("IsPermissionInGroup(testpermission1.2, TestGroup1) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup1") ? "true" : "false"); + LOG("IsPermissionInGroup(testpermission1.2, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup2") ? "true" : "false"); + LOG("IsPermissionInGroup(testpermission1.3, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.3", "TestGroup2") ? "true" : "false"); + LOG("IsPlayerRankSet(%s) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID) ? "true" : "false"); + LOG("IsPlayerRankSet(%s1) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID + "1") ? "true" : "false"); + LOG("GroupExists(TestGroup1) = %s", m_Mgr.GroupExists("TestGroup1") ? "true" : "false"); + LOG("GroupExists(TestGroup3) = %s", m_Mgr.GroupExists("TestGroup3") ? "true" : "false"); + LOG("RankExists(TestRank) = %s", m_Mgr.RankExists("TestRank") ? "true" : "false"); + LOG("RankExists(NonexistentRank) = %s", m_Mgr.RankExists("NonexistentRank") ? "true" : "false"); + + // Test the assignments above: + LOG("After-assignment test:"); + ReportPlayer(UUID); + + LOG("Done."); } - void ReportPlayer(const AString & a_PlayerName) + void ReportPlayer(const AString & a_PlayerUUID) { // Get the player's UUID and rank: - AString UUID = m_API.GetUUIDFromPlayerName(a_PlayerName); - std::cout << "Player " << a_PlayerName << " has UUID '" << UUID <<"'." << std::endl; - std::cout << " Rank: '" << m_Mgr.GetPlayerRankName(UUID) << "'." << std::endl; + LOG(" Rank: '%s'", m_Mgr.GetPlayerRankName(a_PlayerUUID).c_str()); // List all the permission groups for the player: - AStringVector Groups = m_Mgr.GetPlayerGroups(UUID); - std::cout << " Groups(" << Groups.size() << "):" << std::endl; + AStringVector Groups = m_Mgr.GetPlayerGroups(a_PlayerUUID); + LOG(" Groups(%u):", (unsigned)Groups.size()); for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) { - std::cout << " '" << *itr << "'." << std::endl; + LOG(" '%s'" , itr->c_str()); } // for itr - Groups[] // List all the permissions for the player: - AStringVector Permissions = m_Mgr.GetPlayerPermissions(UUID); - std::cout << " Permissions(" << Permissions.size() << "):" << std::endl; + AStringVector Permissions = m_Mgr.GetPlayerPermissions(a_PlayerUUID); + LOG(" Permissions(%u):", (unsigned)Permissions.size()); for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) { - std::cout << " '" << *itr << "'." << std::endl; + LOG(" '%s'", itr->c_str()); } // for itr - Groups[] - - std::cout << "Done." << std::endl; } protected: cRankManager m_Mgr; - cMojangAPI m_API; } g_RankMgrTest; //*/ @@ -70,7 +96,7 @@ cRankManager::cRankManager(void) : m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) { // Create the DB tables, if they don't exist: - m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgPostfix, MsgNameColorCode)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgSuffix, MsgNameColorCode)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PermGroup (PermGroupID INTEGER PRIMARY KEY, Name)"); m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)"); @@ -85,15 +111,23 @@ cRankManager::cRankManager(void) : AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) { - SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?"); - stmt.bind(1, a_PlayerUUID); - stmt.executeStep(); - if (stmt.isDone()) + try { - // No data returned from the DB - return AString(); + SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?"); + stmt.bind(1, a_PlayerUUID); + stmt.executeStep(); + if (stmt.isDone()) + { + // No data returned from the DB + return AString(); + } + return stmt.getColumn(0).getText(); } - return stmt.getColumn(0).getText(); + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Cannot get player rank name: %s", __FUNCTION__, ex.what()); + } + return AString(); } @@ -102,22 +136,29 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) { - // Prepare the DB statement: - SQLite::Statement stmt(m_DB, - "SELECT Group.Name FROM Group " - "LEFT JOIN RankGroups " - "ON Group.GroupID = RankGroups.GroupID " - "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankGroups.RankID " - "WHERE PlayerRank.PlayerUUID = ?" - ); - stmt.bind(1, a_PlayerUUID); - - // Execute and get results: AStringVector res; - while (stmt.executeStep()) + try { - res.push_back(stmt.getColumn(0).getText()); + // Prepare the DB statement: + SQLite::Statement stmt(m_DB, + "SELECT PermGroup.Name FROM PermGroup " + "LEFT JOIN RankPermGroup " + "ON PermGroup.PermGroupID = RankPermGroup.PermGroupID " + "LEFT JOIN PlayerRank " + "ON PlayerRank.RankID = RankPermGroup.RankID " + "WHERE PlayerRank.PlayerUUID = ?" + ); + stmt.bind(1, a_PlayerUUID); + + // Execute and get results: + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Cannot get player groups: %s", __FUNCTION__, ex.what()); } return res; } @@ -128,22 +169,29 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) { - // Prepare the DB statement: - SQLite::Statement stmt(m_DB, - "SELECT PermissionItem.Permission FROM PermissionItem " - "LEFT JOIN RankGroups " - "ON PermissionItem.GroupID = RankGroups.GroupID " - "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankGroups.RankID " - "WHERE PlayerRank.PlayerUUID = ?" - ); - stmt.bind(1, a_PlayerUUID); - - // Execute and get results: AStringVector res; - while (stmt.executeStep()) + try { - res.push_back(stmt.getColumn(0).getText()); + // Prepare the DB statement: + SQLite::Statement stmt(m_DB, + "SELECT PermissionItem.Permission FROM PermissionItem " + "LEFT JOIN RankPermGroup " + "ON PermissionItem.PermGroupID = RankPermGroup.PermGroupID " + "LEFT JOIN PlayerRank " + "ON PlayerRank.RankID = RankPermGroup.RankID " + "WHERE PlayerRank.PlayerUUID = ?" + ); + stmt.bind(1, a_PlayerUUID); + + // Execute and get results: + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Cannot get player permissions: %s", __FUNCTION__, ex.what()); } return res; } @@ -151,3 +199,575 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) + +AStringVector cRankManager::GetRankGroups(const AString & a_RankName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyGroup", __FUNCTION__)); + return res; +} + + + + + +AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + return res; +} + + + + + +AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + return res; +} + + + + + +AStringVector cRankManager::GetAllRanks(void) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyRank", __FUNCTION__)); + return res; +} + + + + + +AStringVector cRankManager::GetAllGroups(void) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyGroup", __FUNCTION__)); + return res; +} + + + + + +AStringVector cRankManager::GetAllPermissions(void) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + return res; +} + + + + + +void cRankManager::GetPlayerMsgVisuals( + const AString & a_PlayerUUID, + AString & a_MsgPrefix, + AString & a_MsgSuffix, + AString & a_MsgNameColorCode +) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + a_MsgPrefix = Printf("%s: DummyPrefix", __FUNCTION__); + a_MsgSuffix = Printf("%s: DummySuffix", __FUNCTION__); + a_MsgNameColorCode = Printf("%s: DummyMsgNameColorCode", __FUNCTION__); +} + + + + + +void cRankManager::AddRank( + const AString & a_RankName, + const AString & a_MsgPrefix, + const AString & a_MsgSuffix, + const AString & a_MsgNameColorCode +) +{ + try + { + // Check if such a rank name is already used: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (stmt.executeStep()) + { + if (stmt.getColumn(0).getInt() > 0) + { + // Rank already exists, do nothing: + return; + } + } + } + + // Insert a new rank: + SQLite::Statement stmt(m_DB, "INSERT INTO Rank (Name, MsgPrefix, MsgSuffix, MsgNameColorCode) VALUES (?, ?, ?, ?)"); + stmt.bind(1, a_RankName); + stmt.bind(2, a_MsgPrefix); + stmt.bind(3, a_MsgSuffix); + stmt.bind(4, a_MsgNameColorCode); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add a new rank \"%s\".", __FUNCTION__, a_RankName.c_str()); + return; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add a new rank \"%s\": %s", __FUNCTION__, a_RankName.c_str(), ex.what()); + } +} + + + + + +void cRankManager::AddGroup(const AString & a_GroupName) +{ + try + { + // Check if such a rank name is already used: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (stmt.executeStep()) + { + if (stmt.getColumn(0).getInt() > 0) + { + // Group already exists, do nothing: + return; + } + } + } + + // Insert a new rank: + SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)"); + stmt.bind(1, a_GroupName); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, a_GroupName.c_str()); + return; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add a new group \"%s\": %s", __FUNCTION__, a_GroupName.c_str(), ex.what()); + } +} + + + + + +bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName) +{ + try + { + SQLite::Transaction trans(m_DB); + int GroupID, RankID; + + // Get the group's ID: + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (!stmt.executeStep()) + { + LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str()); + return false; + } + GroupID = stmt.getColumn(0); + } + + // Get the rank's ID: + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (!stmt.executeStep()) + { + LOGWARNING("%s: No such rank (%s), aborting.", __FUNCTION__, a_RankName.c_str()); + return false; + } + RankID = stmt.getColumn(0); + } + + // Check if the group is already there: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM RankPermGroup WHERE RankID = ? AND PermGroupID = ?"); + stmt.bind(1, RankID); + stmt.bind(2, GroupID); + if (!stmt.executeStep()) + { + LOGWARNING("%s: Failed to check binding between rank %s and group %s, aborting.", __FUNCTION__, a_RankName.c_str(), a_GroupName.c_str()); + return false; + } + if (stmt.getColumn(0).getInt() > 0) + { + LOGD("%s: Group %s already present in rank %s, skipping and returning success.", + __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str() + ); + return true; + } + } + + // Add the group: + { + SQLite::Statement stmt(m_DB, "INSERT INTO RankPermGroup (RankID, PermGroupID) VALUES (?, ?)"); + stmt.bind(1, RankID); + stmt.bind(2, GroupID); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add group %s to rank %s, aborting.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str()); + return false; + } + } + + // Adding succeeded: + trans.commit(); + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add group %s to rank %s: %s", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str(), ex.what()); + } + return false; +} + + + + + +bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName) +{ + try + { + // Wrapp the entire operation into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the group's ID: + int GroupID; + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (!stmt.executeStep()) + { + LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str()); + return false; + } + GroupID = stmt.getColumn(0).getInt(); + } + + // Check if the permission is already present: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?"); + stmt.bind(1, GroupID); + stmt.bind(2, a_Permission); + if (!stmt.executeStep()) + { + LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str()); + return false; + } + if (stmt.getColumn(0).getInt() > 0) + { + LOGD("%s: Permission %s is already present in group %s, skipping and returning success.", + __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str() + ); + return true; + } + } + + // Add the permission: + { + SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)"); + stmt.bind(1, a_Permission); + stmt.bind(2, GroupID); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add permission %s to group %s, aborting.", __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str()); + return false; + } + } + + // Adding succeeded: + trans.commit(); + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add permission %s to group %s: %s", + __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what() + ); + } + return false; +} + + + + + +void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + +void cRankManager::RemoveGroup(const AString & a_GroupName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + +void cRankManager::RemoveGroupFromRank(const AString & a_RankName, const AString & a_GroupName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + +void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + +bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + return false; +} + + + + + +bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); + return false; +} + + + + + +void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_RankName) +{ + try + { + // Wrap the entire operation into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the rank ID: + int RankID; + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (!stmt.executeStep()) + { + LOGWARNING("%s: There is no rank %s, aborting.", __FUNCTION__, a_RankName.c_str()); + return; + } + RankID = stmt.getColumn(0).getInt(); + } + + // Update the player's rank, if already in DB: + { + SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ? WHERE PlayerUUID = ?"); + stmt.bind(1, RankID); + stmt.bind(2, a_PlayerUUID); + if (stmt.exec() > 0) + { + // Successfully updated the player's rank + trans.commit(); + return; + } + } + + // The player is not yet in the DB, add them: + SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID) VALUES (?, ?)"); + stmt.bind(1, RankID); + stmt.bind(2, a_PlayerUUID); + if (stmt.exec() > 0) + { + // Successfully added the player + trans.commit(); + return; + } + + LOGWARNING("%s: Failed to set player UUID %s to rank %s.", + __FUNCTION__, a_PlayerUUID.c_str(), a_RankName.c_str() + ); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to set player UUID %s to rank %s: %s", + __FUNCTION__, a_PlayerUUID.c_str(), a_RankName.c_str(), ex.what() + ); + } +} + + + + + +void cRankManager::SetRankVisuals( + const AString & a_RankName, + const AString & a_MsgPrefix, + const AString & a_MsgSuffix, + const AString & a_MsgNameColorCode +) +{ + LOGWARNING("%s: Not implemented yet", __FUNCTION__); +} + + + + + +bool cRankManager::RankExists(const AString & a_RankName) +{ + try + { + SQLite::Statement stmt(m_DB, "SELECT * FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (stmt.executeStep()) + { + // The rank was found + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB for rank %s: %s", __FUNCTION__, a_RankName.c_str(), ex.what()); + } + return false; +} + + + + + +bool cRankManager::GroupExists(const AString & a_GroupName) +{ + try + { + SQLite::Statement stmt(m_DB, "SELECT * FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (stmt.executeStep()) + { + // The group was found + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB for group %s: %s", __FUNCTION__, a_GroupName.c_str(), ex.what()); + } + return false; +} + + + + + +bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID) +{ + try + { + SQLite::Statement stmt(m_DB, "SELECT * FROM PlayerRank WHERE PlayerUUID = ?"); + stmt.bind(1, a_PlayerUUID); + if (stmt.executeStep()) + { + // The player UUID was found, they have a rank + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB for player UUID %s: %s", __FUNCTION__, a_PlayerUUID.c_str(), ex.what()); + } + return false; +} + + + + + +bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_RankName) +{ + try + { + SQLite::Statement stmt(m_DB, + "SELECT * FROM Rank " + "LEFT JOIN RankPermGroup ON Rank.RankID = RankPermGroup.RankID " + "LEFT JOIN PermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID " + "WHERE Rank.Name = ? AND PermGroup.Name = ?" + ); + stmt.bind(1, a_RankName); + stmt.bind(2, a_GroupName); + if (stmt.executeStep()) + { + // The group is in the rank + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what()); + } + return false; +} + + + + + +bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName) +{ + try + { + SQLite::Statement stmt(m_DB, + "SELECT * FROM PermissionItem " + "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID " + "WHERE PermissionItem.Permission = ? AND PermGroup.Name = ?" + ); + stmt.bind(1, a_Permission); + stmt.bind(2, a_GroupName); + if (stmt.executeStep()) + { + // The permission is in the group + return true; + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what()); + } + return false; +} + + + + diff --git a/src/RankManager.h b/src/RankManager.h index 0b1db2fb8..0c35b555f 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -68,7 +68,7 @@ public: /** Adds the specified permission group to the specified rank. Fails if the rank or group names are not found. Returns true if successful, false on error. */ - bool AddGroupToRank(const AString & a_RankName, const AString & a_GroupName); + bool AddGroupToRank(const AString & a_GroupName, const AString & a_RankName); /** Adds the specified permission to the specified permission group. Fails if the permission group name is not found. @@ -113,6 +113,22 @@ public: const AString & a_MsgSuffix, const AString & a_MsgNameColorCode ); + + /** Returns true iff the specified rank exists in the DB. */ + bool RankExists(const AString & a_RankName); + + /** Returns true iff the specified group exists in the DB. */ + bool GroupExists(const AString & a_GroupName); + + /** Returns true iff the specified player has a rank assigned to them in the DB. */ + bool IsPlayerRankSet(const AString & a_PlayerUUID); + + /** Returns true iff the specified rank contains the specified group. */ + bool IsGroupInRank(const AString & a_GroupName, const AString & a_RankName); + + /** Returns true iff the specified group contains the specified permission. */ + bool IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName); + protected: SQLite::Database m_DB; From a5b35e09ce1e352d4c57e66750a72335fc60d4b2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 16:38:38 +0200 Subject: [PATCH 006/102] RankMgr: Implemented GetXforY and GetAll APIs. --- src/RankManager.cpp | 171 ++++++++++++++++++++++++++++++++++++++++---- src/RankManager.h | 9 ++- 2 files changed, 162 insertions(+), 18 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index e02e63a24..ec9ac1b1d 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -11,7 +11,7 @@ -/* +//* // This code is for internal testing while developing the cRankManager class static class cRankMgrTest { @@ -53,6 +53,13 @@ public: LOG("GroupExists(TestGroup3) = %s", m_Mgr.GroupExists("TestGroup3") ? "true" : "false"); LOG("RankExists(TestRank) = %s", m_Mgr.RankExists("TestRank") ? "true" : "false"); LOG("RankExists(NonexistentRank) = %s", m_Mgr.RankExists("NonexistentRank") ? "true" : "false"); + ReportRankGroups("TestRank"); + ReportRankGroups("NonexistentRank"); + ReportGroupPermissions("TestGroup1"); + ReportGroupPermissions("NonexistentGroup"); + + // Report the contents of the DB: + ReportAll(); // Test the assignments above: LOG("After-assignment test:"); @@ -61,6 +68,35 @@ public: LOG("Done."); } + + void ReportAll(void) + { + // Report all ranks: + AStringVector Ranks = m_Mgr.GetAllRanks(); + LOG("All ranks (%u):", (unsigned)Ranks.size()); + for (AStringVector::const_iterator itr = Ranks.begin(), end = Ranks.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + + // Report all groups: + AStringVector Groups = m_Mgr.GetAllGroups(); + LOG("All groups (%u):", (unsigned)Groups.size()); + for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + + // Report all permissions: + AStringVector Permissions = m_Mgr.GetAllPermissions(); + LOG("All permissions (%u):", (unsigned)Permissions.size()); + for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + } + + void ReportPlayer(const AString & a_PlayerUUID) { // Get the player's UUID and rank: @@ -68,7 +104,7 @@ public: // List all the permission groups for the player: AStringVector Groups = m_Mgr.GetPlayerGroups(a_PlayerUUID); - LOG(" Groups(%u):", (unsigned)Groups.size()); + LOG(" Groups (%u):", (unsigned)Groups.size()); for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) { LOG(" '%s'" , itr->c_str()); @@ -76,13 +112,41 @@ public: // List all the permissions for the player: AStringVector Permissions = m_Mgr.GetPlayerPermissions(a_PlayerUUID); - LOG(" Permissions(%u):", (unsigned)Permissions.size()); + LOG(" Permissions (%u):", (unsigned)Permissions.size()); for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) { LOG(" '%s'", itr->c_str()); } // for itr - Groups[] } + + void ReportRankGroups(const AString & a_RankName) + { + AStringVector Groups = m_Mgr.GetRankGroups(a_RankName); + LOG("Groups in rank %s: %u", a_RankName.c_str(), (unsigned)Groups.size()); + for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + AStringVector Permissions = m_Mgr.GetRankPermissions(a_RankName); + LOG("Permissions in rank %s: %u", a_RankName.c_str(), (unsigned)Permissions.size()); + for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + } + + + void ReportGroupPermissions(const AString & a_GroupName) + { + AStringVector Permissions = m_Mgr.GetGroupPermissions(a_GroupName); + LOG("Permissions in group %s: %u", a_GroupName.c_str(), (unsigned)Permissions.size()); + for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) + { + LOG(" '%s'", itr->c_str()); + } + } + protected: cRankManager m_Mgr; } g_RankMgrTest; @@ -202,9 +266,25 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) AStringVector cRankManager::GetRankGroups(const AString & a_RankName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyGroup", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, + "SELECT PermGroup.Name FROM PermGroup " + "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID " + "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID " + "WHERE Rank.Name = ?" + ); + stmt.bind(1, a_RankName); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get rank groups from DB: %s", __FUNCTION__, ex.what()); + } return res; } @@ -214,9 +294,24 @@ AStringVector cRankManager::GetRankGroups(const AString & a_RankName) AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, + "SELECT PermissionItem.Permission FROM PermissionItem " + "LEFT JOIN PermGroup ON PermGroup.PermGroupID = PermissionItem.PermGroupID " + "WHERE PermGroup.Name = ?" + ); + stmt.bind(1, a_GroupName); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get group permissions from DB: %s", __FUNCTION__, ex.what()); + } return res; } @@ -226,9 +321,25 @@ AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, + "SELECT PermissionItem.Permission FROM PermissionItem " + "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermissionItem.PermGroupID " + "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID " + "WHERE Rank.Name = ?" + ); + stmt.bind(1, a_RankName); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get rank permissions from DB: %s", __FUNCTION__, ex.what()); + } return res; } @@ -238,9 +349,19 @@ AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) AStringVector cRankManager::GetAllRanks(void) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyRank", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, "SELECT Name FROM Rank"); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what()); + } return res; } @@ -250,9 +371,19 @@ AStringVector cRankManager::GetAllRanks(void) AStringVector cRankManager::GetAllGroups(void) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyGroup", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, "SELECT Name FROM PermGroup"); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get groups from DB: %s", __FUNCTION__, ex.what()); + } return res; } @@ -262,9 +393,19 @@ AStringVector cRankManager::GetAllGroups(void) AStringVector cRankManager::GetAllPermissions(void) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); AStringVector res; - res.push_back(Printf("%s: DummyPermission", __FUNCTION__)); + try + { + SQLite::Statement stmt(m_DB, "SELECT Permission FROM PermissionItem"); + while (stmt.executeStep()) + { + res.push_back(stmt.getColumn(0).getText()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get permissions from DB: %s", __FUNCTION__, ex.what()); + } return res; } diff --git a/src/RankManager.h b/src/RankManager.h index 0c35b555f..9a1828275 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -28,13 +28,16 @@ public: /** Returns the permissions that the specified player has assigned to them. */ AStringVector GetPlayerPermissions(const AString & a_PlayerUUID); - /** Returns the names of groups that the specified rank has assigned to it. */ + /** Returns the names of groups that the specified rank has assigned to it. + Returns an empty vector if the rank doesn't exist. */ AStringVector GetRankGroups(const AString & a_RankName); - /** Returns the permissions that the specified group has assigned to it. */ + /** Returns the permissions that the specified group has assigned to it. + Returns an empty vector if the group doesn't exist. */ AStringVector GetGroupPermissions(const AString & a_GroupName); - /** Returns all permissions that the specified rank has assigned to it, through all its groups. */ + /** Returns all permissions that the specified rank has assigned to it, through all its groups. + Returns an empty vector if the rank doesn't exist. Any non-existent groups are ignored. */ AStringVector GetRankPermissions(const AString & a_RankName); /** Returns the names of all defined ranks. */ From 89333c5870efb438a38786fd67b82daff0482d9a Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 21:30:47 +0200 Subject: [PATCH 007/102] RankMgr: Finished API implementation. --- src/RankManager.cpp | 421 ++++++++++++++++++++++++++++++++++++++++---- src/RankManager.h | 18 +- 2 files changed, 401 insertions(+), 38 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index ec9ac1b1d..8a3b19c15 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -11,7 +11,7 @@ -//* +/* // This code is for internal testing while developing the cRankManager class static class cRankMgrTest { @@ -30,30 +30,35 @@ public: // Add a rank, a few groups and permissions and set the player to use them: LOG("Adding data..."); - m_Mgr.AddRank("TestRank", "[test]", "[/test]", "7"); + m_Mgr.AddRank("TestRank1", "[test]", "[/test]", "7"); + m_Mgr.AddRank("TestRank2", "[t2]", "[/t2]", "8"); m_Mgr.AddGroup("TestGroup1"); m_Mgr.AddGroup("TestGroup2"); - m_Mgr.AddGroupToRank("TestGroup1", "TestRank"); - m_Mgr.AddGroupToRank("TestGroup2", "TestRank"); + m_Mgr.AddGroupToRank("TestGroup1", "TestRank1"); + m_Mgr.AddGroupToRank("TestGroup2", "TestRank1"); + m_Mgr.AddGroupToRank("TestGroup2", "TestRank2"); m_Mgr.AddPermissionToGroup("testpermission1.1", "TestGroup1"); m_Mgr.AddPermissionToGroup("testpermission1.2", "TestGroup1"); + m_Mgr.AddPermissionToGroup("testpermission1.3", "TestGroup1"); + m_Mgr.AddPermissionToGroup("common", "TestGroup1"); m_Mgr.AddPermissionToGroup("testpermission2.1", "TestGroup2"); - m_Mgr.SetPlayerRank(UUID, "TestRank"); + m_Mgr.AddPermissionToGroup("common", "TestGroup2"); + m_Mgr.SetPlayerRank(UUID, "xoft", "TestRank1"); // Test the added data: LOG("Testing the added data:"); - LOG("IsGroupInRank(TestGroup1, TestRank) = %s", m_Mgr.IsGroupInRank("TestGroup1", "TestRank") ? "true" : "false"); - LOG("IsGroupInRank(TestGroup3, TestRank) = %s", m_Mgr.IsGroupInRank("TestGroup3", "TestRank") ? "true" : "false"); - LOG("IsPermissionInGroup(testpermission1.2, TestGroup1) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup1") ? "true" : "false"); - LOG("IsPermissionInGroup(testpermission1.2, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup2") ? "true" : "false"); - LOG("IsPermissionInGroup(testpermission1.3, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.3", "TestGroup2") ? "true" : "false"); + LOG("IsGroupInRank(TestGroup1, TestRank1) = %s", m_Mgr.IsGroupInRank("TestGroup1", "TestRank1") ? "true" : "false"); + LOG("IsGroupInRank(TestGroup3, TestRank1) = %s", m_Mgr.IsGroupInRank("TestGroup3", "TestRank1") ? "true" : "false"); + LOG("IsPermissionInGroup(testpermission1.2, TestGroup1) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup1") ? "true" : "false"); // Existing permission, in group + LOG("IsPermissionInGroup(testpermission1.2, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup2") ? "true" : "false"); // Existing permission, not in group + LOG("IsPermissionInGroup(testpermission1.9, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.9", "TestGroup2") ? "true" : "false"); // Non-existing permission LOG("IsPlayerRankSet(%s) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID) ? "true" : "false"); LOG("IsPlayerRankSet(%s1) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID + "1") ? "true" : "false"); LOG("GroupExists(TestGroup1) = %s", m_Mgr.GroupExists("TestGroup1") ? "true" : "false"); LOG("GroupExists(TestGroup3) = %s", m_Mgr.GroupExists("TestGroup3") ? "true" : "false"); - LOG("RankExists(TestRank) = %s", m_Mgr.RankExists("TestRank") ? "true" : "false"); + LOG("RankExists(TestRank1) = %s", m_Mgr.RankExists("TestRank1") ? "true" : "false"); LOG("RankExists(NonexistentRank) = %s", m_Mgr.RankExists("NonexistentRank") ? "true" : "false"); - ReportRankGroups("TestRank"); + ReportRankGroups("TestRank1"); ReportRankGroups("NonexistentRank"); ReportGroupPermissions("TestGroup1"); ReportGroupPermissions("NonexistentGroup"); @@ -64,7 +69,65 @@ public: // Test the assignments above: LOG("After-assignment test:"); ReportPlayer(UUID); + + // Test removing a permission from a group: + LOG("Removing permission testpermission1.3 from group TestGroup1."); + m_Mgr.RemovePermissionFromGroup("testpermission1.3", "TestGroup1"); + ReportGroupPermissions("TestGroup1"); + LOG("Removing permission common from group TestGroup1."); + m_Mgr.RemovePermissionFromGroup("common", "TestGroup1"); + ReportGroupPermissions("TestGroup1"); // Check that it's not present + ReportGroupPermissions("TestGroup2"); // Check that it's still present here + + // Test removing a group from rank: + LOG("Removing group TestGroup2 from rank TestRank1."); + m_Mgr.RemoveGroupFromRank("TestGroup2", "TestRank1"); + ReportRankGroups("TestRank1"); + LOG("Removing group TestGroup3 from rank TestRank1."); + m_Mgr.RemoveGroupFromRank("TestGroup3", "TestRank1"); + ReportRankGroups("TestRank1"); + + // Test re-adding the groups: + LOG("Re-adding groups to TestRank1."); + m_Mgr.AddGroupToRank("TestGroup1", "TestRank1"); + m_Mgr.AddGroupToRank("TestGroup2", "TestRank1"); + ReportRankGroups("TestRank1"); + + // Test removing a group altogether: + LOG("Removing group TestGroup2"); + m_Mgr.RemoveGroup("TestGroup2"); + ReportAll(); + + // Test removing a rank: + LOG("Removing rank TestRank2, replacing with rank TestRank1."); + m_Mgr.RemoveRank("TestRank2", "TestRank1"); + ReportAll(); + LOG("Removing rank Test altogether."); + m_Mgr.RemoveRank("Test", ""); + ReportAll(); + // Test renaming a rank: + LOG("Renaming rank TestRank1 to Test"); + m_Mgr.RenameRank("TestRank1", "Test"); + ReportRankGroups("TestRank1"); + ReportRankGroups("Test"); + LOG("Player after renaming:"); + ReportPlayer(UUID); + + // Test renaming a group: + LOG("Renaming group TestGroup1 to Test"); + m_Mgr.RenameGroup("TestGroup1", "Test"); + ReportGroupPermissions("TestGroup1"); + ReportGroupPermissions("Test"); + LOG("Player after renaming:"); + ReportPlayer(UUID); + m_Mgr.RenameGroup("Test", "TestGroup1"); + + // Test removing the rank in favor of another one: + m_Mgr.RemoveRank("Test", "TestRank2"); + LOG("After-removal test:"); + ReportPlayer(UUID); + LOG("Done."); } @@ -238,7 +301,7 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) { // Prepare the DB statement: SQLite::Statement stmt(m_DB, - "SELECT PermissionItem.Permission FROM PermissionItem " + "SELECT DISTINCT(PermissionItem.Permission) FROM PermissionItem " "LEFT JOIN RankPermGroup " "ON PermissionItem.PermGroupID = RankPermGroup.PermGroupID " "LEFT JOIN PlayerRank " @@ -396,7 +459,7 @@ AStringVector cRankManager::GetAllPermissions(void) AStringVector res; try { - SQLite::Statement stmt(m_DB, "SELECT Permission FROM PermissionItem"); + SQLite::Statement stmt(m_DB, "SELECT DISTINCT(Permission) FROM PermissionItem"); while (stmt.executeStep()) { res.push_back(stmt.getColumn(0).getText()); @@ -413,17 +476,43 @@ AStringVector cRankManager::GetAllPermissions(void) -void cRankManager::GetPlayerMsgVisuals( +bool cRankManager::GetPlayerMsgVisuals( const AString & a_PlayerUUID, AString & a_MsgPrefix, AString & a_MsgSuffix, AString & a_MsgNameColorCode ) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); - a_MsgPrefix = Printf("%s: DummyPrefix", __FUNCTION__); - a_MsgSuffix = Printf("%s: DummySuffix", __FUNCTION__); - a_MsgNameColorCode = Printf("%s: DummyMsgNameColorCode", __FUNCTION__); + AStringVector res; + try + { + SQLite::Statement stmt(m_DB, + "SELECT Rank.MsgPrefix, Rank.MsgSuffix, Rank.MsgNameColorCode FROM Rank " + "LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID " + "WHERE PlayerRank.PlayerUUID = ?" + ); + stmt.bind(1, a_PlayerUUID); + if (!stmt.executeStep()) + { + LOGD("%s: Player UUID %s not found in the DB, returning empty values.", __FUNCTION__, a_PlayerUUID.c_str()); + a_MsgPrefix.clear(); + a_MsgSuffix.clear(); + a_MsgNameColorCode.clear(); + return false; + } + a_MsgPrefix = stmt.getColumn(0).getText(); + a_MsgSuffix = stmt.getColumn(1).getText(); + a_MsgNameColorCode = stmt.getColumn(2).getText(); + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get ranks from DB: %s. Returning empty values.", __FUNCTION__, ex.what()); + } + a_MsgPrefix.clear(); + a_MsgSuffix.clear(); + a_MsgNameColorCode.clear(); + return false; } @@ -659,7 +748,73 @@ bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AStr void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the RankID for the rank being removed: + int RemoveRankID; + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Rank %s was not found. Skipping.", __FUNCTION__, a_RankName.c_str()); + return; + } + RemoveRankID = stmt.getColumn(0).getInt(); + } + + // Get the RankID for the replacement rank: + int ReplacementRankID = -1; + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_ReplacementRankName); + if (stmt.executeStep()) + { + ReplacementRankID = stmt.getColumn(0).getInt(); + } + } + + // Remove the rank's bindings to groups: + { + SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE RankID = ?"); + stmt.bind(1, RemoveRankID); + stmt.exec(); + } + + // Adjust players: + if (ReplacementRankID == -1) + { + // No replacement, just delete all the players that have the rank: + SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE RankID = ?"); + stmt.bind(1, RemoveRankID); + stmt.exec(); + } + else + { + // Replacement available, change all the player records: + SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ? WHERE RankID = ?"); + stmt.bind(1, ReplacementRankID); + stmt.bind(2, RemoveRankID); + stmt.exec(); + } + + // Remove the rank from the DB: + { + SQLite::Statement stmt(m_DB, "DELETE FROM Rank WHERE RankID = ?"); + stmt.bind(1, RemoveRankID); + stmt.exec(); + } + + trans.commit(); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove rank from DB: %s", __FUNCTION__, ex.what()); + } } @@ -668,16 +823,105 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl void cRankManager::RemoveGroup(const AString & a_GroupName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the ID of the group: + int GroupID; + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str()); + return; + } + GroupID = stmt.getColumn(0).getInt(); + } + + // Remove all permissions from the group: + { + SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ?"); + stmt.bind(1, GroupID); + stmt.exec(); + } + + // Remove the group from all ranks that contain it: + { + SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?"); + stmt.bind(1, GroupID); + stmt.exec(); + } + + // Remove the group itself: + { + SQLite::Statement stmt(m_DB, "DELETE FROM PermGroup WHERE PermGroupID = ?"); + stmt.bind(1, GroupID); + stmt.exec(); + } + + trans.commit(); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove group %s from DB: %s", __FUNCTION__, a_GroupName.c_str(), ex.what()); + } } -void cRankManager::RemoveGroupFromRank(const AString & a_RankName, const AString & a_GroupName) +void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the IDs of the group and the rank: + int GroupID, RankID; + { + SQLite::Statement stmt(m_DB, + "SELECT PermGroup.PermGroupID, Rank.RankID FROM PermGroup " + "LEFT JOIN RankPermGroup ON RankPermGroup.PermGroupID = PermGroup.PermGroupID " + "LEFT JOIN Rank ON Rank.RankID = RankPermGroup.RankID " + "WHERE PermGroup.Name = ? AND Rank.Name = ?" + ); + stmt.bind(1, a_GroupName); + stmt.bind(2, a_RankName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Group %s was not found in rank %s, skipping.", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str()); + return; + } + GroupID = stmt.getColumn(0).getInt(); + RankID = stmt.getColumn(1).getInt(); + } + + // Remove the group from all ranks that contain it: + { + SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ?"); + stmt.bind(1, GroupID); + stmt.exec(); + } + + // Remove the group-to-rank binding: + { + SQLite::Statement stmt(m_DB, "DELETE FROM RankPermGroup WHERE PermGroupID = ? AND RankID = ?"); + stmt.bind(1, GroupID); + stmt.bind(1, RankID); + stmt.exec(); + } + + trans.commit(); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove group %s from rank %s in the DB: %s", __FUNCTION__, a_GroupName.c_str(), a_RankName.c_str(), ex.what()); + } } @@ -686,7 +930,40 @@ void cRankManager::RemoveGroupFromRank(const AString & a_RankName, const AString void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the ID of the group: + int GroupID; + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Group %s was not found, skipping.", __FUNCTION__, a_GroupName.c_str()); + return; + } + GroupID = stmt.getColumn(0).getInt(); + } + + // Remove the permission from the group: + { + SQLite::Statement stmt(m_DB, "DELETE FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?"); + stmt.bind(1, GroupID); + stmt.bind(2, a_Permission); + stmt.exec(); + } + + trans.commit(); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove permission %s from group %s in DB: %s", + __FUNCTION__, a_Permission.c_str(), a_GroupName.c_str(), ex.what() + ); + } } @@ -695,7 +972,39 @@ void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Check that NewName doesn't exist: + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_NewName); + if (stmt.executeStep()) + { + LOGD("%s: Rank %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str()); + return false; + } + } + + // Rename: + bool res; + { + SQLite::Statement stmt(m_DB, "UPDATE Rank SET Name = ? WHERE Name = ?"); + stmt.bind(1, a_NewName); + stmt.bind(2, a_OldName); + res = (stmt.exec() > 0); + } + + trans.commit(); + return res; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to rename rank %s to %s in DB: %s", + __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what()); + } return false; } @@ -705,7 +1014,39 @@ bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewNa bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + try + { + // Wrap everything into a transaction: + SQLite::Transaction trans(m_DB); + + // Check that NewName doesn't exist: + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_NewName); + if (stmt.executeStep()) + { + LOGD("%s: Group %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str()); + return false; + } + } + + // Rename: + bool res; + { + SQLite::Statement stmt(m_DB, "UPDATE PermGroup SET Name = ? WHERE Name = ?"); + stmt.bind(1, a_NewName); + stmt.bind(2, a_OldName); + res = (stmt.exec() > 0); + } + + trans.commit(); + return res; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to rename group %s to %s in DB: %s", + __FUNCTION__, a_OldName.c_str(), a_NewName.c_str(), ex.what()); + } return false; } @@ -713,7 +1054,7 @@ bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewN -void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_RankName) +void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName) { try { @@ -735,9 +1076,10 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a // Update the player's rank, if already in DB: { - SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ? WHERE PlayerUUID = ?"); + SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ?, PlayerName = ? WHERE PlayerUUID = ?"); stmt.bind(1, RankID); - stmt.bind(2, a_PlayerUUID); + stmt.bind(2, a_PlayerName); + stmt.bind(3, a_PlayerUUID); if (stmt.exec() > 0) { // Successfully updated the player's rank @@ -747,9 +1089,10 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a } // The player is not yet in the DB, add them: - SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID) VALUES (?, ?)"); + SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID, PlayerName) VALUES (?, ?, ?)"); stmt.bind(1, RankID); stmt.bind(2, a_PlayerUUID); + stmt.bind(3, a_PlayerName); if (stmt.exec() > 0) { // Successfully added the player @@ -780,7 +1123,23 @@ void cRankManager::SetRankVisuals( const AString & a_MsgNameColorCode ) { - LOGWARNING("%s: Not implemented yet", __FUNCTION__); + AStringVector res; + try + { + SQLite::Statement stmt(m_DB, "UPDATE Rank SET MsgPrefix = ?, MsgSuffix = ?, MsgNameColorCode = ? WHERE Name = ?"); + stmt.bind(1, a_MsgPrefix); + stmt.bind(2, a_MsgSuffix); + stmt.bind(1, a_MsgNameColorCode); + stmt.bind(2, a_RankName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Rank %s not found, visuals not set.", __FUNCTION__, a_RankName.c_str()); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what()); + } } diff --git a/src/RankManager.h b/src/RankManager.h index 9a1828275..e13febdac 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -49,8 +49,9 @@ public: /** Returns all the distinct permissions that are stored in the DB. */ AStringVector GetAllPermissions(void); - /** Returns the message visuals (prefix, postfix, color) for the specified player. */ - void GetPlayerMsgVisuals( + /** Returns the message visuals (prefix, postfix, color) for the specified player. + Returns true if the visuals were read from the DB, false if not (player not found etc). */ + bool GetPlayerMsgVisuals( const AString & a_PlayerUUID, AString & a_MsgPrefix, AString & a_MsgSuffix, @@ -79,7 +80,9 @@ public: bool AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName); /** Removes the specified rank. - All players assigned to that rank will be re-assigned to a_ReplacementRankName, unless it is empty. */ + All players assigned to that rank will be re-assigned to a_ReplacementRankName. + If a_ReplacementRankName is empty or not a valid rank, the player will be removed from the DB, + which means they will receive the default rank the next time they are queried. */ void RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName); /** Removes the specified group completely. @@ -88,7 +91,7 @@ public: /** Removes the specified group from the specified rank. The group will stay defined, even if no rank is using it. */ - void RemoveGroupFromRank(const AString & a_RankName, const AString & a_GroupName); + void RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName); /** Removes the specified permission from the specified group. */ void RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName); @@ -104,10 +107,11 @@ public: bool RenameGroup(const AString & a_OldName, const AString & a_NewName); /** Sets the specified player's rank. - If the player already had rank assigned to them, it is overwritten with the new rank. + If the player already had rank assigned to them, it is overwritten with the new rank and name. Note that this doesn't change the cPlayer if the player is already connected, you need to update all the - cPlayer instances manually. */ - void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_RankName); + cPlayer instances manually. + The PlayerName is provided for reference, so that GetRankPlayerNames() can work. */ + void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName); /** Sets the message visuals of an existing rank. No action if the rank name is not found. */ void SetRankVisuals( From 3df7d8446c4d5387475a8d6c2f1c3d5ab28b28eb Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 23:11:42 +0200 Subject: [PATCH 008/102] cLuaState: Added GetStackValues() auto-generated templates. These will read consecutive values off the stack, each value of a type independent of the other values. Auto-generated because we don't have variadic templates in C++03. --- src/Bindings/gen_LuaState_Call.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index 17bae82b3..a5d09d4f1 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -182,6 +182,33 @@ for _, combination in ipairs(Combinations) do WriteOverload(f, combination[1], combination[2]) end +-- Generate the cLuaState::GetStackValues() multi-param templates: +for i = 2, 6 do + f:write("/** Reads ", i, " consecutive values off the stack */\ntemplate <\n") + + -- Write the template function header: + local txt = {} + for idx = 1, i do + table.insert(txt, "\ttypename ArgT" .. idx) + end + f:write(table.concat(txt, ",\n")) + + -- Write the argument declarations: + txt = {} + f:write("\n>\nvoid GetStackValues(\n\tint a_BeginPos,\n") + for idx = 1, i do + table.insert(txt, "\tArgT" .. idx .. " & Arg" .. idx) + end + f:write(table.concat(txt, ",\n")) + + -- Write the function body: + f:write("\n)\n{\n") + for idx = 1, i do + f:write("\tGetStackValue(a_BeginPos + ", idx - 1, ", Arg", idx, ");\n") + end + f:write("}\n\n\n\n\n\n") +end + -- Close the generated file f:close() From f1dc299fdb6d2460437608ce79da4db9d0bde7f1 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 23:12:22 +0200 Subject: [PATCH 009/102] Exported cRankManager to LuaAPI. --- src/Bindings/CMakeLists.txt | 1 + src/Bindings/ManualBindings.cpp | 2 + src/Bindings/ManualBindings.h | 19 +- src/Bindings/ManualBindings_RankManager.cpp | 870 ++++++++++++++++++++ src/Root.h | 3 + 5 files changed, 894 insertions(+), 1 deletion(-) create mode 100644 src/Bindings/ManualBindings_RankManager.cpp diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index a2b381a26..4b8df52f6 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -11,6 +11,7 @@ SET (SRCS LuaState.cpp LuaWindow.cpp ManualBindings.cpp + ManualBindings_RankManager.cpp Plugin.cpp PluginLua.cpp PluginManager.cpp diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 042ffb19e..5563fb14a 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -3262,6 +3262,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_function(tolua_S, "md5", tolua_md5); + + BindRankManager(tolua_S); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index 36161c6a2..0302b9503 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -1,8 +1,25 @@ #pragma once struct lua_State; + + + + + + +/** Provides namespace for the bindings. */ class ManualBindings { public: - static void Bind( lua_State* tolua_S); + /** Binds all the manually implemented functions to tolua_S. */ + static void Bind(lua_State * tolua_S); + +protected: + /** Binds the manually implemented cRankManager glue code to tolua_S. + Implemented in ManualBindings_RankManager.cpp. */ + static void BindRankManager(lua_State * tolua_S); }; + + + + diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp new file mode 100644 index 000000000..daa810cd4 --- /dev/null +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -0,0 +1,870 @@ + +// ManualBindings_RankManager.cpp + +// Implements the cRankManager Lua bindings + +#include "Globals.h" +#include "ManualBindings.h" +#include "../Root.h" +#include "tolua++/include/tolua++.h" +#include "LuaState.h" + + + + + +/** Binds cRankManager::AddGroup */ +static int tolua_cRankManager_AddGroup(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Read the params: + AString GroupName; + S.GetStackValue(2, GroupName); + + // Add the group: + cRoot::Get()->GetRankManager().AddGroup(GroupName); + return 0; +} + + + + + +/** Binds cRankManager::AddGroup */ +static int tolua_cRankManager_AddGroupToRank(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Read the params: + AString GroupName, RankName; + S.GetStackValues(2, GroupName, RankName); + + // Add the group to the rank: + cRoot::Get()->GetRankManager().AddGroupToRank(GroupName, RankName); + return 0; +} + + + + + +/** Binds cRankManager::AddPermissionToGroup */ +static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Read the params: + AString GroupName, Permission; + S.GetStackValues(2, Permission, GroupName); + + // Add the group to the rank: + cRoot::Get()->GetRankManager().AddPermissionToGroup(Permission, GroupName); + return 0; +} + + + + + +/** Binds cRankManager::AddRank */ +static int tolua_cRankManager_AddRank(lua_State * L) +{ + // function signature: + // cRankManager:AddRank(RankName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Read the params: + AString RankName, MsgPrefix, MsgSuffix, MsgNameColorCode; + S.GetStackValues(2, RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + + // Add the rank: + cRoot::Get()->GetRankManager().AddRank(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + return 0; +} + + + + + +/** Binds cRankManager::GetAllGroups */ +static int tolua_cRankManager_GetAllGroups(lua_State * L) +{ + // function signature: + // cRankManager:GetAllGroups() -> arraytable of GroupNames + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the groups: + AStringVector Groups = cRoot::Get()->GetRankManager().GetAllGroups(); + + // Push the results: + S.Push(Groups); + return 1; +} + + + + + +/** Binds cRankManager::GetAllPermissions */ +static int tolua_cRankManager_GetAllPermissions(lua_State * L) +{ + // function signature: + // cRankManager:GetAllPermissions() -> arraytable of Permissions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager().GetAllPermissions(); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + +/** Binds cRankManager::GetAllRanks */ +static int tolua_cRankManager_GetAllRanks(lua_State * L) +{ + // function signature: + // cRankManager:GetAllRanks() -> arraytable of RankNames + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the ranks: + AStringVector Ranks = cRoot::Get()->GetRankManager().GetAllRanks(); + + // Push the results: + S.Push(Ranks); + return 1; +} + + + + + +/** Binds cRankManager::GetGroupPermissions */ +static int tolua_cRankManager_GetGroupPermissions(lua_State * L) +{ + // function signature: + // cRankManager:GetGroupPermissions(GroupName) -> arraytable of permissions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString GroupName; + S.GetStackValue(2, GroupName); + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager().GetGroupPermissions(GroupName); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + +/** Binds cRankManager::GetPlayerGroups */ +static int tolua_cRankManager_GetPlayerGroups(lua_State * L) +{ + // function signature: + // cRankManager:GetPlayerGroups(PlayerUUID) -> arraytable of GroupNames + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the groups: + AStringVector Groups = cRoot::Get()->GetRankManager().GetPlayerGroups(PlayerUUID); + + // Push the results: + S.Push(Groups); + return 1; +} + + + + + +/** Binds cRankManager::GetPlayerMsgVisuals */ +static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L) +{ + // function signature: + // cRankManager:GetPlayerMsgVisuals(PlayerUUID) -> string, string, string + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the permissions: + AString MsgPrefix, MsgSuffix, MsgNameColorCode; + cRoot::Get()->GetRankManager().GetPlayerMsgVisuals(PlayerUUID, MsgPrefix, MsgSuffix, MsgNameColorCode); + + // Push the results: + S.Push(MsgPrefix); + S.Push(MsgSuffix); + S.Push(MsgNameColorCode); + return 3; +} + + + + + +/** Binds cRankManager::GetPlayerPermissions */ +static int tolua_cRankManager_GetPlayerPermissions(lua_State * L) +{ + // function signature: + // cRankManager:GetPlayerPermissions(PlayerUUID) -> arraytable of permissions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager().GetPlayerPermissions(PlayerUUID); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + +/** Binds cRankManager::GetPlayerRankName */ +static int tolua_cRankManager_GetPlayerRankName(lua_State * L) +{ + // function signature: + // cRankManager:GetPlayerRankName(PlayerUUID) -> string + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the rank name: + AString RankName = cRoot::Get()->GetRankManager().GetPlayerRankName(PlayerUUID); + + // Push the result: + S.Push(RankName); + return 1; +} + + + + + +/** Binds cRankManager::GetRankGroups */ +static int tolua_cRankManager_GetRankGroups(lua_State * L) +{ + // function signature: + // cRankManager:GetRankGroups(RankName) -> arraytable of groupnames + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the groups: + AStringVector Groups = cRoot::Get()->GetRankManager().GetRankGroups(RankName); + + // Push the results: + S.Push(Groups); + return 1; +} + + + + + +/** Binds cRankManager::GetRankPermissions */ +static int tolua_cRankManager_GetRankPermissions(lua_State * L) +{ + // function signature: + // cRankManager:GetRankPermissions(RankName) -> arraytable of permissions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager().GetRankPermissions(RankName); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + +/** Binds cRankManager::GroupExists */ +static int tolua_cRankManager_GroupExists(lua_State * L) +{ + // function signature: + // cRankManager:GroupExists(GroupName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString GroupName; + S.GetStackValue(2, GroupName); + + // Get the response: + bool res = cRoot::Get()->GetRankManager().GroupExists(GroupName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::IsGroupInRank */ +static int tolua_cRankManager_IsGroupInRank(lua_State * L) +{ + // function signature: + // cRankManager:IsGroupInRank(GroupName, RankName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, RankName; + S.GetStackValues(2, GroupName, RankName); + + // Get the response: + bool res = cRoot::Get()->GetRankManager().IsGroupInRank(GroupName, RankName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::IsPermissionInGroup */ +static int tolua_cRankManager_IsPermissionInGroup(lua_State * L) +{ + // function signature: + // cRankManager:IsPermissionInGroup(Permission, GroupName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, Permission; + S.GetStackValues(2, Permission, GroupName); + + // Get the response: + bool res = cRoot::Get()->GetRankManager().IsPermissionInGroup(Permission, GroupName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::IsPlayerRankSet */ +static int tolua_cRankManager_IsPlayerRankSet(lua_State * L) +{ + // function signature: + // cRankManager:IsPlayerRankSet(PlayerUUID) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the response: + bool res = cRoot::Get()->GetRankManager().IsPlayerRankSet(PlayerUUID); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::RankExists */ +static int tolua_cRankManager_RankExists(lua_State * L) +{ + // function signature: + // cRankManager:RankExists(RankName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the response: + bool res = cRoot::Get()->GetRankManager().RankExists(RankName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::RemoveGroup */ +static int tolua_cRankManager_RemoveGroup(lua_State * L) +{ + // function signature: + // cRankManager:RemoveGroup(GroupName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString GroupName; + S.GetStackValue(2, GroupName); + + // Remove the group: + cRoot::Get()->GetRankManager().RemoveGroup(GroupName); + return 0; +} + + + + + +/** Binds cRankManager::RemoveGroupFromRank */ +static int tolua_cRankManager_RemoveGroupFromRank(lua_State * L) +{ + // function signature: + // cRankManager:RemoveGroupFromRank(GroupName, RankName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, RankName; + S.GetStackValues(2, GroupName, RankName); + + // Remove the group: + cRoot::Get()->GetRankManager().RemoveGroupFromRank(GroupName, RankName); + return 0; +} + + + + + +/** Binds cRankManager::RemovePermissionFromGroup */ +static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) +{ + // function signature: + // cRankManager:RemovePermissionFromGroup(Permission, GroupName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, Permission; + S.GetStackValues(2, Permission, GroupName); + + // Remove the group: + cRoot::Get()->GetRankManager().RemovePermissionFromGroup(Permission, GroupName); + return 0; +} + + + + + +/** Binds cRankManager::RemoveRank */ +static int tolua_cRankManager_RemoveRank(lua_State * L) +{ + // function signature: + // cRankManager:RemoveRank(RankName, [ReplacementRankName]) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + // Param 3 is otpional, defaults to nil -> empty string + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString RankName, ReplacementRankName; + S.GetStackValues(2, RankName, ReplacementRankName); + + // Remove the rank: + cRoot::Get()->GetRankManager().RemoveRank(RankName, ReplacementRankName); + return 0; +} + + + + + +/** Binds cRankManager::RenameGroup */ +static int tolua_cRankManager_RenameGroup(lua_State * L) +{ + // function signature: + // cRankManager:RenameGroup(OldName, NewName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString OldName, NewName; + S.GetStackValues(2, OldName, NewName); + + // Remove the group: + bool res = cRoot::Get()->GetRankManager().RenameGroup(OldName, NewName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::RenameRank */ +static int tolua_cRankManager_RenameRank(lua_State * L) +{ + // function signature: + // cRankManager:RenameRank(OldName, NewName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString OldName, NewName; + S.GetStackValues(2, OldName, NewName); + + // Remove the rank: + bool res = cRoot::Get()->GetRankManager().RenameRank(OldName, NewName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + +/** Binds cRankManager::SetPlayerRank */ +static int tolua_cRankManager_SetPlayerRank(lua_State * L) +{ + // function signature: + // cRankManager:SetPlayerRank(PlayerUUID, PlayerName, RankName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 4) || + !S.CheckParamEnd(5) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID, PlayerName, RankName; + S.GetStackValues(2, PlayerUUID, PlayerName, RankName); + + // Set the rank: + cRoot::Get()->GetRankManager().SetPlayerRank(PlayerUUID, PlayerName, RankName); + return 0; +} + + + + + +/** Binds cRankManager::SetRankVisuals */ +static int tolua_cRankManager_SetRankVisuals(lua_State * L) +{ + // function signature: + // cRankManager:SetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 5) || + !S.CheckParamEnd(6) + ) + { + return 0; + } + + // Get the params: + AString RankName, MsgPrefix, MsgSuffix, MsgNameColorCode; + S.GetStackValues(2, RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + + // Set the visuals: + cRoot::Get()->GetRankManager().SetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + return 0; +} + + + + + +void ManualBindings::BindRankManager(lua_State * tolua_S) +{ + // Create the cRankManager class in the API: + tolua_usertype(tolua_S, "cRankManager"); + tolua_cclass(tolua_S, "cRankManager", "cRankManager", "", NULL); + + // Fill in the functions (alpha-sorted): + tolua_beginmodule(tolua_S, "cRankManager"); + tolua_function(tolua_S, "AddGroup", tolua_cRankManager_AddGroup); + tolua_function(tolua_S, "AddGroupToRank", tolua_cRankManager_AddGroupToRank); + tolua_function(tolua_S, "AddPermissionToGroup", tolua_cRankManager_AddPermissionToGroup); + tolua_function(tolua_S, "AddRank", tolua_cRankManager_AddRank); + tolua_function(tolua_S, "GetAllGroups", tolua_cRankManager_GetAllGroups); + tolua_function(tolua_S, "GetAllPermissions", tolua_cRankManager_GetAllPermissions); + tolua_function(tolua_S, "GetAllRanks", tolua_cRankManager_GetAllRanks); + tolua_function(tolua_S, "GetGroupPermissions", tolua_cRankManager_GetGroupPermissions); + tolua_function(tolua_S, "GetPlayerGroups", tolua_cRankManager_GetPlayerGroups); + tolua_function(tolua_S, "GetPlayerMsgVisuals", tolua_cRankManager_GetPlayerMsgVisuals); + tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); + tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); + tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); + tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); + tolua_function(tolua_S, "GroupExists", tolua_cRankManager_GroupExists); + tolua_function(tolua_S, "IsGroupInRank", tolua_cRankManager_IsGroupInRank); + tolua_function(tolua_S, "IsPermissionInGroup", tolua_cRankManager_IsPermissionInGroup); + tolua_function(tolua_S, "IsPlayerRankSet", tolua_cRankManager_IsPlayerRankSet); + tolua_function(tolua_S, "RankExists", tolua_cRankManager_RankExists); + tolua_function(tolua_S, "RemoveGroup", tolua_cRankManager_RemoveGroup); + tolua_function(tolua_S, "RemoveGroupFromRank", tolua_cRankManager_RemoveGroupFromRank); + tolua_function(tolua_S, "RemovePermissionFromGroup", tolua_cRankManager_RemovePermissionFromGroup); + tolua_function(tolua_S, "RemoveRank", tolua_cRankManager_RemoveRank); + tolua_function(tolua_S, "RenameGroup", tolua_cRankManager_RenameGroup); + tolua_function(tolua_S, "RenameRank", tolua_cRankManager_RenameRank); + tolua_function(tolua_S, "SetPlayerRank", tolua_cRankManager_SetPlayerRank); + tolua_function(tolua_S, "SetRankVisuals", tolua_cRankManager_SetRankVisuals); + tolua_endmodule(tolua_S); +} + + + + diff --git a/src/Root.h b/src/Root.h index 1cd175ab4..68469c72f 100644 --- a/src/Root.h +++ b/src/Root.h @@ -5,6 +5,7 @@ #include "Protocol/MojangAPI.h" #include "HTTPServer/HTTPServer.h" #include "Defines.h" +#include "RankManager.h" @@ -89,6 +90,7 @@ public: cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } + cRankManager & GetRankManager (void) { return m_RankManager; } /** Queues a console command for execution through the cServer class. The command will be executed in the tick thread @@ -194,6 +196,7 @@ private: cPluginManager * m_PluginManager; cAuthenticator m_Authenticator; cMojangAPI m_MojangAPI; + cRankManager m_RankManager; cHTTPServer m_HTTPServer; cMCLogger * m_Log; From 251f0d5b97bc36fa3c335bf6a1b03aa22503fa47 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 23:13:43 +0200 Subject: [PATCH 010/102] Debuggers: Simple cRankManager test case. --- MCServer/Plugins/Debuggers/Debuggers.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 7e220952e..a87511fb9 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -81,6 +81,7 @@ function Initialize(Plugin) TestBlockAreasString() TestStringBase64() TestUUIDFromName() + TestRankMgr() --[[ -- Test cCompositeChat usage in console-logging: @@ -352,6 +353,18 @@ end +function TestRankMgr() + LOG("Testing the rank manager") + cRankManager:AddRank("LuaRank") + cRankManager:AddGroup("LuaTestGroup") + cRankManager:AddGroupToRank("LuaTestGroup", "LuaRank") + cRankManager:AddPermissionToGroup("luaperm", "LuaTestGroup") +end + + + + + function TestSQLiteBindings() LOG("Testing SQLite bindings..."); From 0001a7c9fc2359078968565a8ab464509362b776 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 17:36:19 +0200 Subject: [PATCH 011/102] RankMgr: Added GetRankVisuals() function. --- src/Bindings/ManualBindings_RankManager.cpp | 40 +++++++++++++++++++-- src/RankManager.cpp | 37 +++++++++++++++++-- src/RankManager.h | 9 +++++ 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index daa810cd4..d17672dcb 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -100,8 +100,8 @@ static int tolua_cRankManager_AddRank(lua_State * L) cLuaState S(L); if ( !S.CheckParamUserTable(1, "cRankManager") || - !S.CheckParamString(2) || - !S.CheckParamEnd(3) + !S.CheckParamString(2, 5) || + !S.CheckParamEnd(6) ) { return 0; @@ -396,6 +396,41 @@ static int tolua_cRankManager_GetRankGroups(lua_State * L) +/** Binds cRankManager::GetRankVisuals */ +static int tolua_cRankManager_GetRankVisuals(lua_State * L) +{ + // function signature: + // cRankManager:GetRankVisuals(RankName) -> MsgPrefix, MsgSuffix, MsgNameColorCode + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the visuals: + AString MsgPrefix, MsgSuffix, MsgNameColorCode; + cRoot::Get()->GetRankManager().GetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); + + // Push the results: + S.Push(MsgPrefix); + S.Push(MsgSuffix); + S.Push(MsgNameColorCode); + return 3; +} + + + + + /** Binds cRankManager::GetRankPermissions */ static int tolua_cRankManager_GetRankPermissions(lua_State * L) { @@ -848,6 +883,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); + tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); tolua_function(tolua_S, "GroupExists", tolua_cRankManager_GroupExists); tolua_function(tolua_S, "IsGroupInRank", tolua_cRankManager_IsGroupInRank); diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 8a3b19c15..3627afadb 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -1123,14 +1123,13 @@ void cRankManager::SetRankVisuals( const AString & a_MsgNameColorCode ) { - AStringVector res; try { SQLite::Statement stmt(m_DB, "UPDATE Rank SET MsgPrefix = ?, MsgSuffix = ?, MsgNameColorCode = ? WHERE Name = ?"); stmt.bind(1, a_MsgPrefix); stmt.bind(2, a_MsgSuffix); - stmt.bind(1, a_MsgNameColorCode); - stmt.bind(2, a_RankName); + stmt.bind(3, a_MsgNameColorCode); + stmt.bind(4, a_RankName); if (!stmt.executeStep()) { LOGINFO("%s: Rank %s not found, visuals not set.", __FUNCTION__, a_RankName.c_str()); @@ -1146,6 +1145,38 @@ void cRankManager::SetRankVisuals( +bool cRankManager::GetRankVisuals( + const AString & a_RankName, + AString & a_MsgPrefix, + AString & a_MsgSuffix, + AString & a_MsgNameColorCode +) +{ + try + { + SQLite::Statement stmt(m_DB, "SELECT MsgPrefix, MsgSuffix, MsgNameColorCode FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (!stmt.executeStep()) + { + // Rank not found + return false; + } + a_MsgPrefix = stmt.getColumn(0).getText(); + a_MsgSuffix = stmt.getColumn(1).getText(); + a_MsgNameColorCode = stmt.getColumn(2).getText(); + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to get ranks from DB: %s", __FUNCTION__, ex.what()); + } + return false; +} + + + + + bool cRankManager::RankExists(const AString & a_RankName) { try diff --git a/src/RankManager.h b/src/RankManager.h index e13febdac..0a43bfe5d 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -121,6 +121,15 @@ public: const AString & a_MsgNameColorCode ); + /** Returns the message visuals of an existing rank. + Returns true if successful, false on error (rank doesn't exist). */ + bool GetRankVisuals( + const AString & a_RankName, + AString & a_MsgPrefix, + AString & a_MsgSuffix, + AString & a_MsgNameColorCode + ); + /** Returns true iff the specified rank exists in the DB. */ bool RankExists(const AString & a_RankName); From 2ab8e763927070eef76963d42933a0d9b87191c2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 22:34:59 +0200 Subject: [PATCH 012/102] WebAdmin: Added GetURLEncodedString(). --- src/WebAdmin.cpp | 32 ++++++++++++++++++++++++++++++++ src/WebAdmin.h | 5 ++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index f5dc6fde7..ab6925e55 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -444,6 +444,38 @@ AString cWebAdmin::GetHTMLEscapedString(const AString & a_Input) +AString cWebAdmin::GetURLEncodedString(const AString & a_Input) +{ + // Translation table from nibble to hex: + static const char Hex[] = "0123456789abcdef"; + + // Preallocate the output to match input: + AString dst; + size_t len = a_Input.length(); + dst.reserve(len); + + // Loop over input and substitute whatever is needed: + for (size_t i = 0; i < len; i++) + { + char ch = a_Input[i]; + if (isalnum(ch) || (ch == '-') || (ch == '_') || (ch == '.') || (ch == '~')) + { + dst.push_back(ch); + } + else + { + dst.push_back('%'); + dst.push_back(Hex[(ch >> 4) & 0x0f]); + dst.push_back(Hex[ch & 0x0f]); + } + } // for i - a_Input[] + return dst; +} + + + + + AString cWebAdmin::GetBaseURL(const AStringVector & a_URLSplit) { AString BaseURL = "./"; diff --git a/src/WebAdmin.h b/src/WebAdmin.h index d679a097c..018a27b69 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -134,6 +134,9 @@ public: /** Escapes text passed into it, so it can be embedded into html. */ static AString GetHTMLEscapedString(const AString & a_Input); + + /** Escapes the string for use in an URL */ + static AString GetURLEncodedString(const AString & a_Input); AString GetIPv4Ports(void) const { return m_PortsIPv4; } AString GetIPv6Ports(void) const { return m_PortsIPv6; } @@ -141,7 +144,7 @@ public: // tolua_end /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */ - AString GetBaseURL(const AStringVector& a_URLSplit); + static AString GetBaseURL(const AStringVector & a_URLSplit); protected: /** Common base class for request body data handlers */ From 50359ce65670badb72879f09fc9b2f77b2cbeae6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 22:54:43 +0200 Subject: [PATCH 013/102] WebAdmin: Manually exported string conversion functions. ToLua generated an extra return value for GetHTMLEscapedString() and GetURLEncodedString(), making them difficult to use. --- src/Bindings/ManualBindings.cpp | 60 ++++++++++++++++++++++++++++++++- src/WebAdmin.h | 10 +++--- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index f50bdd7de..c8eb5d138 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2128,6 +2128,62 @@ static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S) +/** Binding for cWebAdmin::GetHTMLEscapedString. +Manual code required because ToLua generates an extra return value */ +static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S) +{ + // Check the param types: + cLuaState S(tolua_S); + if ( + !S.CheckParamUserTable(1, "cWebAdmin") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the parameters: + AString Input; + S.GetStackValue(2, Input); + + // Convert and return: + S.Push(cWebAdmin::GetHTMLEscapedString(Input)); + return 1; +} + + + + + +/** Binding for cWebAdmin::GetURLEncodedString. +Manual code required because ToLua generates an extra return value */ +static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S) +{ + // Check the param types: + cLuaState S(tolua_S); + if ( + !S.CheckParamUserTable(1, "cWebAdmin") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the parameters: + AString Input; + S.GetStackValue(2, Input); + + // Convert and return: + S.Push(cWebAdmin::GetURLEncodedString(Input)); + return 1; +} + + + + + static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) { cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S, 1, NULL); @@ -3264,7 +3320,9 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWebAdmin"); - tolua_function(tolua_S, "GetPlugins", tolua_cWebAdmin_GetPlugins); + tolua_function(tolua_S, "GetHTMLEscapedString", tolua_AllToLua_cWebAdmin_GetHTMLEscapedString); + tolua_function(tolua_S, "GetPlugins", tolua_cWebAdmin_GetPlugins); + tolua_function(tolua_S, "GetURLEncodedString", tolua_AllToLua_cWebAdmin_GetURLEncodedString); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWebPlugin"); diff --git a/src/WebAdmin.h b/src/WebAdmin.h index 018a27b69..f48e8ce9e 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -132,17 +132,17 @@ public: /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */ AString GetBaseURL(const AString & a_URL); + AString GetIPv4Ports(void) const { return m_PortsIPv4; } + AString GetIPv6Ports(void) const { return m_PortsIPv6; } + + // tolua_end + /** Escapes text passed into it, so it can be embedded into html. */ static AString GetHTMLEscapedString(const AString & a_Input); /** Escapes the string for use in an URL */ static AString GetURLEncodedString(const AString & a_Input); - AString GetIPv4Ports(void) const { return m_PortsIPv4; } - AString GetIPv6Ports(void) const { return m_PortsIPv6; } - - // tolua_end - /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */ static AString GetBaseURL(const AStringVector & a_URLSplit); From af202c2363131d343d38a1f04850cfd711aef61e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 22:55:38 +0200 Subject: [PATCH 014/102] Debuggers: Disabled UUID and RankMgr tests. --- MCServer/Plugins/Debuggers/Debuggers.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index a87511fb9..81cf02f3c 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -80,8 +80,8 @@ function Initialize(Plugin) TestBlockAreasString() TestStringBase64() - TestUUIDFromName() - TestRankMgr() + -- TestUUIDFromName() + -- TestRankMgr() --[[ -- Test cCompositeChat usage in console-logging: From e0b45c189328d668f5177e529abe99387fc49cf3 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 11 Aug 2014 16:06:40 +0200 Subject: [PATCH 015/102] Fixed unchecked return values. --- src/Bindings/ManualBindings_RankManager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index d17672dcb..b109b0097 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -57,8 +57,8 @@ static int tolua_cRankManager_AddGroupToRank(lua_State * L) S.GetStackValues(2, GroupName, RankName); // Add the group to the rank: - cRoot::Get()->GetRankManager().AddGroupToRank(GroupName, RankName); - return 0; + S.Push(cRoot::Get()->GetRankManager().AddGroupToRank(GroupName, RankName)); + return 1; } @@ -287,7 +287,10 @@ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L) // Get the permissions: AString MsgPrefix, MsgSuffix, MsgNameColorCode; - cRoot::Get()->GetRankManager().GetPlayerMsgVisuals(PlayerUUID, MsgPrefix, MsgSuffix, MsgNameColorCode); + if (!cRoot::Get()->GetRankManager().GetPlayerMsgVisuals(PlayerUUID, MsgPrefix, MsgSuffix, MsgNameColorCode)) + { + return 0; + } // Push the results: S.Push(MsgPrefix); From e110f7226895b1629f72a52c7953d8f00a1f63c6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 09:53:33 +0200 Subject: [PATCH 016/102] RankMgr: Initial migration code. --- src/RankManager.cpp | 542 +++++++++++++++++++++++++++++++++++++++++++- src/RankManager.h | 28 +++ src/Root.cpp | 1 + 3 files changed, 569 insertions(+), 2 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 3627afadb..9809f1d6c 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -6,6 +6,8 @@ #include "Globals.h" #include "RankManager.h" #include "SQLiteCpp/Transaction.h" +#include "inifile/iniFile.h" +#include "Protocol/MojangAPI.h" @@ -219,9 +221,367 @@ protected: -cRankManager::cRankManager(void) : - m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) +//////////////////////////////////////////////////////////////////////////////// +/** Migrates from groups.ini and users.ini into the rankmanager DB */ +class cRankManagerIniMigrator { +public: + cRankManagerIniMigrator(cRankManager & a_RankManager, cMojangAPI & a_MojangAPI) : + m_RankManager(a_RankManager), + m_MojangAPI(a_MojangAPI) + { + } + + + + /** Performs the complete migration from INI files to DB. */ + bool Migrate(void) + { + LOGD("Reading groups..."); + if (!ReadGroups()) + { + return false; + } + LOGD("Cleaning groups inheritance..."); + CleanGroupInheritance(); + LOGD("Creating groups..."); + CreateGroups(); + + LOGD("Reading users..."); + if (!ReadUsers()) + { + return false; + } + LOGD("Cleaning user groups..."); + CleanUserGroups(); + LOGD("Resolving user UUIDs..."); + ResolveUserUUIDs(); + + LOGD("Setting ranks..."); + SetRanks(); + + return true; + } + +protected: + + /** Container for a group read from an INI file. */ + struct sGroup + { + AString m_Name; + AString m_Color; + AStringVector m_Inherits; + AStringVector m_Permissions; + + sGroup(void) {} + + sGroup(const AString & a_Name, const AString & a_Color, const AStringVector & a_Inherits, const AStringVector & a_Permissions): + m_Name(a_Name), + m_Color(a_Color), + m_Inherits(a_Inherits), + m_Permissions(a_Permissions) + { + } + }; + typedef std::map sGroupMap; + + + /** Container for a single user read from an INI file. */ + struct sUser + { + AString m_Name; + AStringVector m_Groups; + + /** Assigned by ResolveUserUUIDs() */ + AString m_UUID; + + + sUser(void) {} + + sUser(const AString & a_Name, const AStringVector & a_Groups): + m_Name(a_Name), + m_Groups(a_Groups) + { + } + }; + typedef std::map sUserMap; + + typedef std::map cStringMap; + + + /** The parent Rank manager where we will create the groups, ranks and players */ + cRankManager & m_RankManager; + + /** The player name to UUID resolver */ + cMojangAPI & m_MojangAPI; + + /** List of all groups read from the ini file */ + sGroupMap m_Groups; + + /** List of all players read from the ini file. */ + sUserMap m_Users; + + /** Maps lists of groups to rank names. + Each group list is either a simple "" if there's only one group, + or ",,...", where the secondary groups are + lowercased and alpha-sorted. This makes the group lists comparable for equivalence, simply by comparing + their string names. + The ranks are named "" for single-group players, and "AutoMigratedRank_N" for the composite ranks, + where N is a unique number. */ + cStringMap m_GroupsToRanks; + + + + /** Reads the groups from the "groups.ini" file into m_Groups */ + bool ReadGroups(void) + { + // Read the file: + cIniFile Groups; + if (!Groups.ReadFile("groups.ini")) + { + return false; + } + + // Read all the groups into a map: + int NumGroups = Groups.GetNumKeys(); + for (int i = 0; i < NumGroups; i++) + { + AString GroupName = Groups.GetKeyName(i); + AString lcGroupName = StrToLower(GroupName); + if (m_Groups.find(lcGroupName) != m_Groups.end()) + { + LOGINFO("groups.ini contains a duplicate definition of group %s, ignoring the latter.", GroupName.c_str()); + continue; + } + m_Groups[lcGroupName] = sGroup( + GroupName, + Groups.GetValue(GroupName, "Color", ""), + StringSplitAndTrim(Groups.GetValue(GroupName, "Inherits"), ","), + StringSplitAndTrim(Groups.GetValue(GroupName, "Permissions"), ",") + ); + } // for i - Groups' keys + return true; + } + + + + /** Removes non-existent groups from all the groups' inheritance */ + void CleanGroupInheritance(void) + { + for (sGroupMap::iterator itrG = m_Groups.begin(), endG = m_Groups.end(); itrG != endG; ++itrG) + { + AStringVector & Inherits = itrG->second.m_Inherits; + for (AStringVector::iterator itrI = Inherits.begin(); itrI != Inherits.end();) + { + AString lcInherits = StrToLower(*itrI); + if (m_Groups.find(lcInherits) != m_Groups.end()) + { + // Inherited group exists, continue checking the next one + ++itrI; + continue; + } + // Inherited group doesn't exist, remove it from the list: + LOGWARNING("RankMigrator: Group \"%s\" inherits from a non-existent group \"%s\", this inheritance will be ignored.", + itrG->second.m_Name.c_str(), itrI->c_str() + ); + AStringVector::iterator itrI2 = itrI; + ++itrI2; + Inherits.erase(itrI); + itrI = itrI2; + } // for itrI - Inherits[] + } // for itrG - m_Groups[] + } + + + + /** Reads the users from the "users.ini" file into m_Users */ + bool ReadUsers(void) + { + // Read the file: + cIniFile Users; + if (!Users.ReadFile("users.ini")) + { + return false; + } + + // Read all the users into a map: + int NumUsers = Users.GetNumKeys(); + for (int i = 0; i < NumUsers; i++) + { + AString UserName = Users.GetKeyName(i); + AString lcUserName = StrToLower(UserName); + if (m_Users.find(lcUserName) != m_Users.end()) + { + LOGINFO("users.ini contains a duplicate definition of user %s, ignoring the latter.", UserName.c_str()); + continue; + } + m_Users[lcUserName] = sUser( + UserName, + StringSplitAndTrim(Users.GetValue(UserName, "Groups", ""), ",") + ); + } // for i - Users' keys + return true; + } + + + + /** Removes non-existent groups from each user's definition. */ + void CleanUserGroups(void) + { + for (sUserMap::iterator itrU = m_Users.begin(), endU = m_Users.end(); itrU != endU; ++itrU) + { + AStringVector & Groups = itrU->second.m_Groups; + for (AStringVector::iterator itrG = Groups.begin(); itrG != Groups.end();) + { + AString lcGroup = StrToLower(*itrG); + if (m_Groups.find(lcGroup) != m_Groups.end()) + { + // Assigned group exists, continue checking the next one + ++itrG; + continue; + } + // Assigned group doesn't exist, remove it from the list: + LOGWARNING("RankMigrator: User \"%s\" is assigned a non-existent group \"%s\", this assignment will be ignored.", + itrU->second.m_Name.c_str(), itrG->c_str() + ); + AStringVector::iterator itrG2 = itrG; + ++itrG2; + Groups.erase(itrG); + itrG = itrG2; + } // for itrG - Groups[] + } // for itrU - m_Users[] + } + + + + /** Creates groups based on m_Groups. + Ignores group inheritance. */ + void CreateGroups(void) + { + // Create each group, with its permissions: + for (sGroupMap::const_iterator itr = m_Groups.begin(), end = m_Groups.end(); itr != end; ++itr) + { + m_RankManager.AddGroup(itr->second.m_Name); + m_RankManager.AddPermissionsToGroup(itr->second.m_Permissions, itr->second.m_Name); + } // for itr - m_Groups[] + } + + + /** Resolves the UUID of each user in m_Users. + If a user doesn't resolve, they are removed and logged in the console. */ + void ResolveUserUUIDs(void) + { + // Resolve all PlayerNames at once (the API doesn't like single-name queries): + AStringVector PlayerNames; + for (sUserMap::const_iterator itr = m_Users.begin(), end = m_Users.end(); itr != end; ++itr) + { + PlayerNames.push_back(itr->second.m_Name); + } + m_MojangAPI.GetUUIDsFromPlayerNames(PlayerNames); + + // Assign the UUIDs back to players, remove those not resolved: + for (sUserMap::iterator itr = m_Users.begin(); itr != m_Users.end(); ) + { + AString UUID = m_MojangAPI.GetUUIDFromPlayerName(itr->second.m_Name); + if (UUID.empty()) + { + LOGWARNING("RankMigrator: Cannot resolve player %s to UUID, player will be left unranked", itr->second.m_Name.c_str()); + sUserMap::iterator itr2 = itr; + ++itr2; + m_Users.erase(itr); + itr = itr2; + } + else + { + itr->second.m_UUID = UUID; + ++itr; + } + } + } + + + + /** Adds the specified groups to the specified ranks. Recurses on the groups' inheritance. */ + void AddGroupsToRank(const AStringVector & a_Groups, const AString & a_RankName) + { + for (AStringVector::const_iterator itr = a_Groups.begin(), end = a_Groups.end(); itr != end; ++itr) + { + // Normalize the group name: + sGroup & Group = m_Groups[StrToLower(*itr)]; + + // Avoid loops, check if the group is already added: + if (m_RankManager.IsGroupInRank(Group.m_Name, a_RankName)) + { + continue; + } + + // Add the group, and all the groups it inherits from recursively: + m_RankManager.AddGroupToRank(Group.m_Name, a_RankName); + AddGroupsToRank(Group.m_Inherits, a_RankName); + } // for itr - a_Groups[] + } + + + + /** Creates a rank for each player, based on the master groups they are assigned. */ + void SetRanks(void) + { + for (sUserMap::const_iterator itr = m_Users.begin(), end = m_Users.end(); itr != end; ++itr) + { + // Ignore users with no groups: + const AStringVector & Groups = itr->second.m_Groups; + if (Groups.empty()) + { + LOGWARNING("RankMigrator: Player %s has no groups assigned to them, skipping the player.", itr->second.m_Name.c_str()); + continue; + } + + // Compose the rank name out of group names: + AString RankName; + for (AStringVector::const_iterator itrG = Groups.begin(), endG = Groups.end(); itrG != endG; ++itrG) + { + AString GroupName = m_Groups[StrToLower(*itrG)].m_Name; // Normalize group name + if (!RankName.empty()) + { + RankName.push_back(','); + } + RankName.append(GroupName); + } // for itrG - Groups[] + + // Create the rank, with al its groups: + if (!m_RankManager.RankExists(RankName)) + { + m_RankManager.AddRank(RankName, "", "", m_Groups[StrToLower(Groups[0])].m_Color); + AddGroupsToRank(Groups, RankName); + } + + // Set the rank to the user: + m_RankManager.SetPlayerRank(itr->second.m_UUID, itr->second.m_Name, RankName); + } // for itr - m_Users[] + } +}; + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cRankManager: + +cRankManager::cRankManager(void) : + m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), + m_IsInitialized(false) +{ +} + + + + + +void cRankManager::Initialize(cMojangAPI & a_MojangAPI) +{ + ASSERT(!m_IsInitialized); // Calling Initialize for the second time? + // Create the DB tables, if they don't exist: m_DB.exec("CREATE TABLE IF NOT EXISTS Rank (RankID INTEGER PRIMARY KEY, Name, MsgPrefix, MsgSuffix, MsgNameColorCode)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PlayerRank (PlayerUUID, PlayerName, RankID INTEGER)"); @@ -229,6 +589,22 @@ cRankManager::cRankManager(void) : m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (PermGroupID INTEGER, Permission)"); + m_IsInitialized = true; + + // Check if tables empty, migrate from ini files then + if (AreDBTablesEmpty()) + { + LOGINFO("There are no ranks, migrating old-style INI files to new DB ranks..."); + LOGINFO("(This might take a while)"); + cRankManagerIniMigrator Migrator(*this, a_MojangAPI); + if (Migrator.Migrate()) + { + LOGINFO("Ranks migrated."); + return; + } + } + + // Migration failed. // TODO: Check if tables empty, add some defaults then } @@ -238,6 +614,8 @@ cRankManager::cRankManager(void) : AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?"); @@ -263,6 +641,8 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -296,6 +676,8 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -329,6 +711,8 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) AStringVector cRankManager::GetRankGroups(const AString & a_RankName) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -357,6 +741,8 @@ AStringVector cRankManager::GetRankGroups(const AString & a_RankName) AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -384,6 +770,8 @@ AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -412,6 +800,8 @@ AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) AStringVector cRankManager::GetAllRanks(void) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -434,6 +824,8 @@ AStringVector cRankManager::GetAllRanks(void) AStringVector cRankManager::GetAllGroups(void) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -456,6 +848,8 @@ AStringVector cRankManager::GetAllGroups(void) AStringVector cRankManager::GetAllPermissions(void) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -483,6 +877,8 @@ bool cRankManager::GetPlayerMsgVisuals( AString & a_MsgNameColorCode ) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -526,6 +922,8 @@ void cRankManager::AddRank( const AString & a_MsgNameColorCode ) { + ASSERT(m_IsInitialized); + try { // Check if such a rank name is already used: @@ -566,6 +964,8 @@ void cRankManager::AddRank( void cRankManager::AddGroup(const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { // Check if such a rank name is already used: @@ -603,6 +1003,8 @@ void cRankManager::AddGroup(const AString & a_GroupName) bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName) { + ASSERT(m_IsInitialized); + try { SQLite::Transaction trans(m_DB); @@ -680,6 +1082,8 @@ bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { // Wrapp the entire operation into a transaction: @@ -746,8 +1150,83 @@ bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AStr +bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, const AString & a_GroupName) +{ + ASSERT(m_IsInitialized); + + try + { + // Wrapp the entire operation into a transaction: + SQLite::Transaction trans(m_DB); + + // Get the group's ID: + int GroupID; + { + SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); + stmt.bind(1, a_GroupName); + if (!stmt.executeStep()) + { + LOGWARNING("%s: No such group (%s), aborting.", __FUNCTION__, a_GroupName.c_str()); + return false; + } + GroupID = stmt.getColumn(0).getInt(); + } + + for (AStringVector::const_iterator itr = a_Permissions.begin(), end = a_Permissions.end(); itr != end; ++itr) + { + // Check if the permission is already present: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermissionItem WHERE PermGroupID = ? AND Permission = ?"); + stmt.bind(1, GroupID); + stmt.bind(2, *itr); + if (!stmt.executeStep()) + { + LOGWARNING("%s: Failed to check binding between permission %s and group %s, aborting.", __FUNCTION__, itr->c_str(), a_GroupName.c_str()); + return false; + } + if (stmt.getColumn(0).getInt() > 0) + { + LOGD("%s: Permission %s is already present in group %s, skipping and returning success.", + __FUNCTION__, itr->c_str(), a_GroupName.c_str() + ); + continue; + } + } + + // Add the permission: + { + SQLite::Statement stmt(m_DB, "INSERT INTO PermissionItem (Permission, PermGroupID) VALUES (?, ?)"); + stmt.bind(1, *itr); + stmt.bind(2, GroupID); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add permission %s to group %s, skipping.", __FUNCTION__, itr->c_str(), a_GroupName.c_str()); + continue; + } + } + } // for itr - a_Permissions[] + + // Adding succeeded: + trans.commit(); + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add permissions to group %s: %s", + __FUNCTION__, a_GroupName.c_str(), ex.what() + ); + } + return false; +} + + + + + void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName) { + ASSERT(m_IsInitialized); + AStringVector res; try { @@ -823,6 +1302,8 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl void cRankManager::RemoveGroup(const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { // Wrap everything into a transaction: @@ -876,6 +1357,8 @@ void cRankManager::RemoveGroup(const AString & a_GroupName) void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName) { + ASSERT(m_IsInitialized); + try { // Wrap everything into a transaction: @@ -930,6 +1413,8 @@ void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AStrin void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { // Wrap everything into a transaction: @@ -972,6 +1457,8 @@ void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName) { + ASSERT(m_IsInitialized); + try { // Wrap everything into a transaction: @@ -1014,6 +1501,8 @@ bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewNa bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName) { + ASSERT(m_IsInitialized); + try { // Wrap everything into a transaction: @@ -1056,6 +1545,8 @@ bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewN void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName) { + ASSERT(m_IsInitialized); + try { // Wrap the entire operation into a transaction: @@ -1123,6 +1614,8 @@ void cRankManager::SetRankVisuals( const AString & a_MsgNameColorCode ) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "UPDATE Rank SET MsgPrefix = ?, MsgSuffix = ?, MsgNameColorCode = ? WHERE Name = ?"); @@ -1152,6 +1645,8 @@ bool cRankManager::GetRankVisuals( AString & a_MsgNameColorCode ) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "SELECT MsgPrefix, MsgSuffix, MsgNameColorCode FROM Rank WHERE Name = ?"); @@ -1179,6 +1674,8 @@ bool cRankManager::GetRankVisuals( bool cRankManager::RankExists(const AString & a_RankName) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "SELECT * FROM Rank WHERE Name = ?"); @@ -1202,6 +1699,8 @@ bool cRankManager::RankExists(const AString & a_RankName) bool cRankManager::GroupExists(const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "SELECT * FROM PermGroup WHERE Name = ?"); @@ -1225,6 +1724,8 @@ bool cRankManager::GroupExists(const AString & a_GroupName) bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, "SELECT * FROM PlayerRank WHERE PlayerUUID = ?"); @@ -1248,6 +1749,8 @@ bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID) bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_RankName) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, @@ -1277,6 +1780,8 @@ bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_ bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName) { + ASSERT(m_IsInitialized); + try { SQLite::Statement stmt(m_DB, @@ -1302,3 +1807,36 @@ bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AStri + +bool cRankManager::AreDBTablesEmpty(void) +{ + return ( + IsDBTableEmpty("Rank") && + IsDBTableEmpty("PlayerRank") && + IsDBTableEmpty("PermGroup") && + IsDBTableEmpty("RankPermGroup") && + IsDBTableEmpty("PermissionItem") + ); +} + + + + + +bool cRankManager::IsDBTableEmpty(const AString & a_TableName) +{ + try + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM " + a_TableName); + return (stmt.executeStep() && (stmt.getColumn(0).getInt() == 0)); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to query DB: %s", __FUNCTION__, ex.what()); + } + return false; +} + + + + diff --git a/src/RankManager.h b/src/RankManager.h index 0a43bfe5d..ffe7638e1 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -14,11 +14,22 @@ +class cMojangAPI; + + + + + class cRankManager { public: + /** Creates the rank manager. Needs to be initialized before other use. */ cRankManager(void); + /** Initializes the rank manager. Performs migration and default-setting if no data is found in the DB. + The a_MojangAPI param is used when migrating from old ini files, to look up player UUIDs. */ + void Initialize(cMojangAPI & a_MojangAPI); + /** Returns the name of the rank that the specified player has assigned to them. */ AString GetPlayerRankName(const AString & a_PlayerUUID); @@ -79,6 +90,11 @@ public: Returns true if successful, false on error. */ bool AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName); + /** Adds the specified permissions to the specified permission group. + Fails if the permission group name is not found. + Returns true if successful, false on error. */ + bool AddPermissionsToGroup(const AStringVector & a_Permissions, const AString & a_GroupName); + /** Removes the specified rank. All players assigned to that rank will be re-assigned to a_ReplacementRankName. If a_ReplacementRankName is empty or not a valid rank, the player will be removed from the DB, @@ -147,7 +163,19 @@ public: protected: + /** The database storage for all the data. */ SQLite::Database m_DB; + + /** Set to true once the manager is initialized. */ + bool m_IsInitialized; + + + /** Returns true if all the DB tables are empty, indicating a fresh new install. */ + bool AreDBTablesEmpty(void); + + /** Returns true iff the specified DB table is empty. + If there's an error while querying, returns false. */ + bool IsDBTableEmpty(const AString & a_TableName); } ; diff --git a/src/Root.cpp b/src/Root.cpp index c20cf0d21..333d92de5 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -156,6 +156,7 @@ void cRoot::Start(void) m_WebAdmin->Init(); LOGD("Loading settings..."); + m_RankManager.Initialize(m_MojangAPI); m_GroupManager = new cGroupManager(); m_CraftingRecipes = new cCraftingRecipes; m_FurnaceRecipe = new cFurnaceRecipe(); From 5e415c5b9565564c41c4f2f4144c6863c106bc46 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 12:33:31 +0200 Subject: [PATCH 017/102] RankMgr: Fixed multithreading issues. Only one thread is allowed to interact with a SQLite::Database object at a time. Additionally, improved performance of the migration by wrapping the entire thing in a transaction. --- src/RankManager.cpp | 128 +++++++++++++++++++++++++++----------------- src/RankManager.h | 32 ++++++++++- 2 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 9809f1d6c..e64a47eb6 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -5,7 +5,6 @@ #include "Globals.h" #include "RankManager.h" -#include "SQLiteCpp/Transaction.h" #include "inifile/iniFile.h" #include "Protocol/MojangAPI.h" @@ -237,6 +236,8 @@ public: /** Performs the complete migration from INI files to DB. */ bool Migrate(void) { + cRankManager::cMassChangeLock Lock(m_RankManager); + LOGD("Reading groups..."); if (!ReadGroups()) { @@ -615,6 +616,7 @@ void cRankManager::Initialize(cMojangAPI & a_MojangAPI) AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -642,6 +644,7 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -677,6 +680,7 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -712,6 +716,7 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) AStringVector cRankManager::GetRankGroups(const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -742,6 +747,7 @@ AStringVector cRankManager::GetRankGroups(const AString & a_RankName) AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -771,6 +777,7 @@ AStringVector cRankManager::GetGroupPermissions(const AString & a_GroupName) AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -801,6 +808,7 @@ AStringVector cRankManager::GetRankPermissions(const AString & a_RankName) AStringVector cRankManager::GetAllRanks(void) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -825,6 +833,7 @@ AStringVector cRankManager::GetAllRanks(void) AStringVector cRankManager::GetAllGroups(void) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -849,6 +858,7 @@ AStringVector cRankManager::GetAllGroups(void) AStringVector cRankManager::GetAllPermissions(void) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -878,6 +888,7 @@ bool cRankManager::GetPlayerMsgVisuals( ) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try @@ -923,6 +934,7 @@ void cRankManager::AddRank( ) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -965,10 +977,11 @@ void cRankManager::AddRank( void cRankManager::AddGroup(const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Check if such a rank name is already used: + // Check if such a group name is already used: { SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?"); stmt.bind(1, a_GroupName); @@ -982,7 +995,7 @@ void cRankManager::AddGroup(const AString & a_GroupName) } } - // Insert a new rank: + // Insert a new group: SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)"); stmt.bind(1, a_GroupName); if (stmt.exec() <= 0) @@ -1001,16 +1014,58 @@ void cRankManager::AddGroup(const AString & a_GroupName) -bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName) +void cRankManager::AddGroups(const AStringVector & a_GroupNames) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + for (AStringVector::const_iterator itr = a_GroupNames.begin(), end = a_GroupNames.end(); itr != end; ++itr) + { + // Check if such the group name is already used: + { + SQLite::Statement stmt(m_DB, "SELECT COUNT(*) FROM PermGroup WHERE Name = ?"); + stmt.bind(1, *itr); + if (stmt.executeStep()) + { + if (stmt.getColumn(0).getInt() > 0) + { + // Group already exists, do nothing: + return; + } + } + } + + // Insert a new group: + SQLite::Statement stmt(m_DB, "INSERT INTO PermGroup (Name) VALUES (?)"); + stmt.bind(1, *itr); + if (stmt.exec() <= 0) + { + LOGWARNING("%s: Failed to add a new group \"%s\".", __FUNCTION__, itr->c_str()); + return; + } + } // for itr - a_GroupNames[] + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to add new groups: %s", __FUNCTION__, ex.what()); + } +} + + + + + +bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a_RankName) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - SQLite::Transaction trans(m_DB); - int GroupID, RankID; - // Get the group's ID: + int GroupID; { SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); stmt.bind(1, a_GroupName); @@ -1023,6 +1078,7 @@ bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a } // Get the rank's ID: + int RankID; { SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); stmt.bind(1, a_RankName); @@ -1066,7 +1122,6 @@ bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a } // Adding succeeded: - trans.commit(); return true; } catch (const SQLite::Exception & ex) @@ -1083,12 +1138,10 @@ bool cRankManager::AddGroupToRank(const AString & a_GroupName, const AString & a bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrapp the entire operation into a transaction: - SQLite::Transaction trans(m_DB); - // Get the group's ID: int GroupID; { @@ -1134,7 +1187,6 @@ bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AStr } // Adding succeeded: - trans.commit(); return true; } catch (const SQLite::Exception & ex) @@ -1153,12 +1205,10 @@ bool cRankManager::AddPermissionToGroup(const AString & a_Permission, const AStr bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrapp the entire operation into a transaction: - SQLite::Transaction trans(m_DB); - // Get the group's ID: int GroupID; { @@ -1207,7 +1257,6 @@ bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, co } // for itr - a_Permissions[] // Adding succeeded: - trans.commit(); return true; } catch (const SQLite::Exception & ex) @@ -1226,13 +1275,11 @@ bool cRankManager::AddPermissionsToGroup(const AStringVector & a_Permissions, co void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); AStringVector res; try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Get the RankID for the rank being removed: int RemoveRankID; { @@ -1287,8 +1334,6 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl stmt.bind(1, RemoveRankID); stmt.exec(); } - - trans.commit(); } catch (const SQLite::Exception & ex) { @@ -1303,12 +1348,10 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl void cRankManager::RemoveGroup(const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Get the ID of the group: int GroupID; { @@ -1342,8 +1385,6 @@ void cRankManager::RemoveGroup(const AString & a_GroupName) stmt.bind(1, GroupID); stmt.exec(); } - - trans.commit(); } catch (const SQLite::Exception & ex) { @@ -1358,12 +1399,10 @@ void cRankManager::RemoveGroup(const AString & a_GroupName) void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Get the IDs of the group and the rank: int GroupID, RankID; { @@ -1398,8 +1437,6 @@ void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AStrin stmt.bind(1, RankID); stmt.exec(); } - - trans.commit(); } catch (const SQLite::Exception & ex) { @@ -1414,12 +1451,10 @@ void cRankManager::RemoveGroupFromRank(const AString & a_GroupName, const AStrin void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Get the ID of the group: int GroupID; { @@ -1440,8 +1475,6 @@ void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const stmt.bind(2, a_Permission); stmt.exec(); } - - trans.commit(); } catch (const SQLite::Exception & ex) { @@ -1458,12 +1491,10 @@ void cRankManager::RemovePermissionFromGroup(const AString & a_Permission, const bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Check that NewName doesn't exist: { SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); @@ -1484,7 +1515,6 @@ bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewNa res = (stmt.exec() > 0); } - trans.commit(); return res; } catch (const SQLite::Exception & ex) @@ -1502,12 +1532,10 @@ bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewNa bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap everything into a transaction: - SQLite::Transaction trans(m_DB); - // Check that NewName doesn't exist: { SQLite::Statement stmt(m_DB, "SELECT PermGroupID FROM PermGroup WHERE Name = ?"); @@ -1528,7 +1556,6 @@ bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewN res = (stmt.exec() > 0); } - trans.commit(); return res; } catch (const SQLite::Exception & ex) @@ -1546,12 +1573,10 @@ bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewN void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { - // Wrap the entire operation into a transaction: - SQLite::Transaction trans(m_DB); - // Get the rank ID: int RankID; { @@ -1574,7 +1599,6 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a if (stmt.exec() > 0) { // Successfully updated the player's rank - trans.commit(); return; } } @@ -1587,7 +1611,6 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a if (stmt.exec() > 0) { // Successfully added the player - trans.commit(); return; } @@ -1615,6 +1638,7 @@ void cRankManager::SetRankVisuals( ) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1646,6 +1670,7 @@ bool cRankManager::GetRankVisuals( ) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1675,6 +1700,7 @@ bool cRankManager::GetRankVisuals( bool cRankManager::RankExists(const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1700,6 +1726,7 @@ bool cRankManager::RankExists(const AString & a_RankName) bool cRankManager::GroupExists(const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1725,6 +1752,7 @@ bool cRankManager::GroupExists(const AString & a_GroupName) bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1750,6 +1778,7 @@ bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID) bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_RankName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { @@ -1781,6 +1810,7 @@ bool cRankManager::IsGroupInRank(const AString & a_GroupName, const AString & a_ bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName) { ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); try { diff --git a/src/RankManager.h b/src/RankManager.h index ffe7638e1..3ccbd2fd4 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -9,6 +9,7 @@ #pragma once #include "SQLiteCpp/Database.h" +#include "SQLiteCpp/Transaction.h" @@ -23,6 +24,29 @@ class cMojangAPI; class cRankManager { public: + /** Acquire this lock to perform mass changes. + Improves performance by wrapping everything into a transaction. + Makes sure that no other thread is accessing the DB. */ + class cMassChangeLock + { + public: + cMassChangeLock(cRankManager & a_RankManager) : + m_Lock(a_RankManager.m_CS), + m_Transaction(a_RankManager.m_DB) + { + } + + ~cMassChangeLock() + { + m_Transaction.commit(); + } + + protected: + cCSLock m_Lock; + SQLite::Transaction m_Transaction; + }; + + /** Creates the rank manager. Needs to be initialized before other use. */ cRankManager(void); @@ -80,6 +104,9 @@ public: /** Adds a new permission group. No action if such a group already exists. */ void AddGroup(const AString & a_GroupName); + /** Bulk-adds groups. Group names that already exist are silently skipped. */ + void AddGroups(const AStringVector & a_GroupNames); + /** Adds the specified permission group to the specified rank. Fails if the rank or group names are not found. Returns true if successful, false on error. */ @@ -163,9 +190,12 @@ public: protected: - /** The database storage for all the data. */ + /** The database storage for all the data. Protected by m_CS. */ SQLite::Database m_DB; + /** The mutex protecting m_DB against multi-threaded access. */ + cCriticalSection m_CS; + /** Set to true once the manager is initialized. */ bool m_IsInitialized; From 8f7b9acb488a2dc4a9c34de499a3cd0e0829ef40 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 12:10:21 +0100 Subject: [PATCH 018/102] Fixed forgotten error checking --- src/CraftingRecipes.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 1a31a6e90..085b6e0d5 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -324,7 +324,11 @@ void cCraftingRecipes::LoadRecipes(void) return; } AString Everything; - f.ReadRestOfFile(Everything); + if (!f.ReadRestOfFile(Everything)) + { + LOGWARNING("Cannot read file \"crafting.txt\", no crafting recipes will be available!"); + return; + } f.Close(); // Split it into lines, then process each line as a single recipe: From c3c3d3a72d7517863f015364e62ca0dff46a6807 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 12:14:55 +0100 Subject: [PATCH 019/102] Fixed type issues in CraftingRecipe.cpp --- src/CraftingRecipes.cpp | 4 ++-- src/CraftingRecipes.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 085b6e0d5..48178eecb 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -83,7 +83,7 @@ cItem & cCraftingGrid::GetItem(int x, int y) const -void cCraftingGrid::SetItem(int x, int y, ENUM_ITEM_ID a_ItemType, int a_ItemCount, short a_ItemHealth) +void cCraftingGrid::SetItem(int x, int y, ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemHealth) { // Accessible through scripting, must verify parameters: if ((x < 0) || (x >= m_Width) || (y < 0) || (y >= m_Height)) @@ -228,7 +228,7 @@ void cCraftingRecipe::Clear(void) -void cCraftingRecipe::SetResult(ENUM_ITEM_ID a_ItemType, int a_ItemCount, short a_ItemHealth) +void cCraftingRecipe::SetResult(ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemHealth) { m_Result = cItem(a_ItemType, a_ItemCount, a_ItemHealth); } diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h index 0250d2f68..fe1e15817 100644 --- a/src/CraftingRecipes.h +++ b/src/CraftingRecipes.h @@ -33,7 +33,7 @@ public: int GetWidth (void) const {return m_Width; } int GetHeight(void) const {return m_Height; } cItem & GetItem (int x, int y) const; - void SetItem (int x, int y, ENUM_ITEM_ID a_ItemType, int a_ItemCount, short a_ItemHealth); + void SetItem (int x, int y, ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemHealth); void SetItem (int x, int y, const cItem & a_Item); void Clear (void); @@ -72,13 +72,13 @@ public: int GetIngredientsHeight(void) const {return m_Ingredients.GetHeight(); } cItem & GetIngredient (int x, int y) const {return m_Ingredients.GetItem(x, y); } const cItem & GetResult (void) const {return m_Result; } - void SetResult (ENUM_ITEM_ID a_ItemType, int a_ItemCount, short a_ItemHealth); + void SetResult (ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemHealth); void SetResult (const cItem & a_Item) { m_Result = a_Item; } - void SetIngredient (int x, int y, ENUM_ITEM_ID a_ItemType, int a_ItemCount, short a_ItemHealth) + void SetIngredient (int x, int y, ENUM_ITEM_ID a_ItemType, char a_ItemCount, short a_ItemHealth) { m_Ingredients.SetItem(x, y, a_ItemType, a_ItemCount, a_ItemHealth); } From 781e1e6264794ec0fddccd37a76f7a78a3fa8b09 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 13:03:56 +0100 Subject: [PATCH 020/102] Fixed Integer pasing warnings in CraftingRecipies.cpp --- src/CraftingRecipes.cpp | 6 ++-- src/StringUtils.h | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 48178eecb..2d80ecaf8 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -392,8 +392,7 @@ void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine } if (ResultSplit.size() > 1) { - Recipe->m_Result.m_ItemCount = atoi(ResultSplit[1].c_str()); - if (Recipe->m_Result.m_ItemCount == 0) + if (!StringToInteger(ResultSplit[1].c_str(), Recipe->m_Result.m_ItemCount)) { LOGWARNING("crafting.txt: line %d: Cannot parse result count, ignoring the recipe.", a_LineNum); LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str()); @@ -445,8 +444,7 @@ bool cCraftingRecipes::ParseItem(const AString & a_String, cItem & a_Item) if (Split.size() > 1) { AString Damage = TrimString(Split[1]); - a_Item.m_ItemDamage = atoi(Damage.c_str()); - if ((a_Item.m_ItemDamage == 0) && (Damage.compare("0") != 0)) + if (!StringToInteger(Damage.c_str(), a_Item.m_ItemDamage)) { // Parsing the number failed return false; diff --git a/src/StringUtils.h b/src/StringUtils.h index 142aaf59b..56ac83942 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -99,6 +99,68 @@ 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); +/// Parses any integer type. Checks bounds and +template +bool StringToInteger(AString a_str, T& a_Num) +{ + size_t i = 0; + T positive = true; + T result = 0; + if (a_str[0] == '+') + { + i++; + } + else if (a_str[0] == '-') + { + i++; + positive = false; + } + if (positive) + { + for(; i <= a_str.size(); i++) + { + if ((a_str[i] <= '0') || (a_str[i] >= '9')) + { + return false; + } + if (std::numeric_limits::max() / 10 < result) + { + return false; + } + result *= 10; + T digit = a_str[i] - '0'; + if (std::numeric_limits::max() - digit < result) + { + return false; + } + result += digit; + } + } + else + { + for(; i <= a_str.size(); i++) + { + if ((a_str[i] <= '0') || (a_str[i] >= '9')) + { + return false; + } + if (std::numeric_limits::min() / 10 > result) + { + return false; + } + result *= 10; + T digit = a_str[i] - '0'; + if (std::numeric_limits::min() + digit > result) + { + return false; + } + result -= digit; + } + } + a_Num = result; + return true; +} + // If you have any other string helper functions, declare them here From fecd607d7496d77a488757871a5abe60f789572b Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 13:15:29 +0100 Subject: [PATCH 021/102] Added missing header --- src/StringUtils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/StringUtils.h b/src/StringUtils.h index 56ac83942..30a193845 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -9,6 +9,7 @@ #pragma once #include +#include From f4d268636a02346acc46c993666fe02bbc1ff0b8 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 13:37:07 +0100 Subject: [PATCH 022/102] Fixed comments --- src/StringUtils.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/StringUtils.h b/src/StringUtils.h index 30a193845..a78f8b0bf 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -100,12 +100,12 @@ 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); -/// Parses any integer type. Checks bounds and +/// Parses any integer type. Checks bounds and returns errors out of band. template -bool StringToInteger(AString a_str, T& a_Num) +bool StringToInteger(const AString& a_str, T& a_Num) { size_t i = 0; - T positive = true; + bool positive = true; T result = 0; if (a_str[0] == '+') { @@ -118,7 +118,7 @@ bool StringToInteger(AString a_str, T& a_Num) } if (positive) { - for(; i <= a_str.size(); i++) + for(size_t size = a_str.size(); i < size; i++) { if ((a_str[i] <= '0') || (a_str[i] >= '9')) { @@ -139,7 +139,7 @@ bool StringToInteger(AString a_str, T& a_Num) } else { - for(; i <= a_str.size(); i++) + for(size_t size = a_str.size(); i < size; i++) { if ((a_str[i] <= '0') || (a_str[i] >= '9')) { From a544c0238ba4c94d78692a7592107f8e510893ee Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Wed, 13 Aug 2014 18:53:23 +0200 Subject: [PATCH 023/102] Implement ability to push minecarts on curved rails --- src/Entities/Minecart.cpp | 74 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index d4eadc5d5..19eaa207f 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -871,11 +871,79 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) return true; } case E_META_RAIL_CURVED_ZM_XM: - case E_META_RAIL_CURVED_ZM_XP: - case E_META_RAIL_CURVED_ZP_XM: case E_META_RAIL_CURVED_ZP_XP: { - // TODO - simply can't be bothered right now + Vector3d Distance( + MinecartCollisionCallback.GetCollidedEntityPosition().x - GetPosX(), + 0, + MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() + ); + + if ( Distance.z == 0. ) Distance.z = 0.0001; + if ( ((Distance.z>=0)&&((Distance.x/Distance.z)>=1)) || ((Distance.z<0)&&((Distance.x/Distance.z)<=1)) ) + { + if ( (-GetSpeedX() * 0.4) < 0.01 ) + { + AddSpeedX( -4/sqrt(2) ); + AddSpeedZ( 4/sqrt(2) ); + } + else + { + SetSpeedX( -GetSpeedX() * 0.4 ); + SetSpeedZ( GetSpeedZ() * 0.4 ); + } + } + else + { + if ((GetSpeedX() * 0.4) < 0.01) + { + AddSpeedX( 4/sqrt(2) ); + AddSpeedZ( -4/sqrt(2) ); + } + else + { + SetSpeedX( GetSpeedX() * 0.4 ); + SetSpeedZ( -GetSpeedZ() * 0.4 ); + } + } + break; + } + case E_META_RAIL_CURVED_ZM_XP: + case E_META_RAIL_CURVED_ZP_XM: + { + Vector3d Distance( + MinecartCollisionCallback.GetCollidedEntityPosition().x - GetPosX(), + 0, + MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() + ); + + if ( Distance.z == 0. ) Distance.z = 0.0001; + if ( ((Distance.z>=0)&&((Distance.x/Distance.z)<=-1)) || ((Distance.z<0)&&((Distance.x/Distance.z)>=-1)) ) + { + if ( (GetSpeedX() * 0.4) < 0.01 ) + { + AddSpeedX( 4/sqrt(2) ); + AddSpeedZ( 4/sqrt(2) ); + } + else + { + SetSpeedX( GetSpeedX() * 0.4 ); + SetSpeedZ( GetSpeedZ() * 0.4 ); + } + } + else + { + if ((-GetSpeedX() * 0.4) < 0.01) + { + AddSpeedX( -4/sqrt(2) ); + AddSpeedZ( -4/sqrt(2) ); + } + else + { + SetSpeedX( -GetSpeedX() * 0.4 ); + SetSpeedZ( -GetSpeedZ() * 0.4 ); + } + } break; } default: break; From 3698c5c8295e6a6a0f37b17f3c04bb118cc58bf6 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Wed, 13 Aug 2014 19:16:00 +0200 Subject: [PATCH 024/102] Fixed braces and intendation errors --- src/Entities/Minecart.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 19eaa207f..5cf56d3d2 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -879,8 +879,12 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() ); - if ( Distance.z == 0. ) Distance.z = 0.0001; - if ( ((Distance.z>=0)&&((Distance.x/Distance.z)>=1)) || ((Distance.z<0)&&((Distance.x/Distance.z)<=1)) ) + if ( Distance.z == 0. ) + { + Distance.z = 0.0001; + } + + if ( ((Distance.z>=0)&&((Distance.x/Distance.z)>=1)) || ((Distance.z<0)&&((Distance.x/Distance.z)<=1)) ) { if ( (-GetSpeedX() * 0.4) < 0.01 ) { @@ -917,7 +921,11 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() ); - if ( Distance.z == 0. ) Distance.z = 0.0001; + if ( Distance.z == 0. ) + { + Distance.z = 0.0001; + } + if ( ((Distance.z>=0)&&((Distance.x/Distance.z)<=-1)) || ((Distance.z<0)&&((Distance.x/Distance.z)>=-1)) ) { if ( (GetSpeedX() * 0.4) < 0.01 ) From 3f117897fbda4eec95ad5cdd728f197840dd7224 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Wed, 13 Aug 2014 19:18:11 +0200 Subject: [PATCH 025/102] Another intendation error --- src/Entities/Minecart.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 5cf56d3d2..cd5e2adaa 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -881,9 +881,9 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) if ( Distance.z == 0. ) { - Distance.z = 0.0001; + Distance.z = 0.0001; } - + if ( ((Distance.z>=0)&&((Distance.x/Distance.z)>=1)) || ((Distance.z<0)&&((Distance.x/Distance.z)<=1)) ) { if ( (-GetSpeedX() * 0.4) < 0.01 ) From 2d2d4ff33b74eefe053cce4d9a5daada65ed496b Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Wed, 13 Aug 2014 19:47:43 +0200 Subject: [PATCH 026/102] Further fixing of coding style errors --- src/Entities/Minecart.cpp | 48 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index cd5e2adaa..45b9782f3 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -879,14 +879,15 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() ); - if ( Distance.z == 0. ) + if (Distance.z == 0.) { Distance.z = 0.0001; } - if ( ((Distance.z>=0)&&((Distance.x/Distance.z)>=1)) || ((Distance.z<0)&&((Distance.x/Distance.z)<=1)) ) + if (((Distance.z >= 0) && ((Distance.x / Distance.z) >= 1)) || + ((Distance.z<0) && ((Distance.x / Distance.z) <= 1))) { - if ( (-GetSpeedX() * 0.4) < 0.01 ) + if ((-GetSpeedX() * 0.4) < 0.01) { AddSpeedX( -4/sqrt(2) ); AddSpeedZ( 4/sqrt(2) ); @@ -897,18 +898,15 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) SetSpeedZ( GetSpeedZ() * 0.4 ); } } + else if ((GetSpeedX() * 0.4) < 0.01) + { + AddSpeedX( 4/sqrt(2) ); + AddSpeedZ( -4/sqrt(2) ); + } else { - if ((GetSpeedX() * 0.4) < 0.01) - { - AddSpeedX( 4/sqrt(2) ); - AddSpeedZ( -4/sqrt(2) ); - } - else - { - SetSpeedX( GetSpeedX() * 0.4 ); - SetSpeedZ( -GetSpeedZ() * 0.4 ); - } + SetSpeedX( GetSpeedX() * 0.4 ); + SetSpeedZ( -GetSpeedZ() * 0.4 ); } break; } @@ -921,14 +919,15 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() ); - if ( Distance.z == 0. ) + if (Distance.z == 0.) { Distance.z = 0.0001; } - if ( ((Distance.z>=0)&&((Distance.x/Distance.z)<=-1)) || ((Distance.z<0)&&((Distance.x/Distance.z)>=-1)) ) + if (((Distance.z >= 0) && ((Distance.x / Distance.z) <= -1)) || + ((Distance.z<0) && ((Distance.x / Distance.z) >= -1))) { - if ( (GetSpeedX() * 0.4) < 0.01 ) + if ((GetSpeedX() * 0.4) < 0.01) { AddSpeedX( 4/sqrt(2) ); AddSpeedZ( 4/sqrt(2) ); @@ -939,18 +938,15 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) SetSpeedZ( GetSpeedZ() * 0.4 ); } } + else if ((-GetSpeedX() * 0.4) < 0.01) + { + AddSpeedX( -4/sqrt(2) ); + AddSpeedZ( -4/sqrt(2) ); + } else { - if ((-GetSpeedX() * 0.4) < 0.01) - { - AddSpeedX( -4/sqrt(2) ); - AddSpeedZ( -4/sqrt(2) ); - } - else - { - SetSpeedX( -GetSpeedX() * 0.4 ); - SetSpeedZ( -GetSpeedZ() * 0.4 ); - } + SetSpeedX( -GetSpeedX() * 0.4 ); + SetSpeedZ( -GetSpeedZ() * 0.4 ); } break; } From e3a74f379fc103f40e6bf85e626d7bac7db236af Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Thu, 14 Aug 2014 14:29:46 +0200 Subject: [PATCH 027/102] Further changes in coding style --- src/Entities/Minecart.cpp | 66 +++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 45b9782f3..8e11d8a07 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -873,80 +873,70 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) case E_META_RAIL_CURVED_ZM_XM: case E_META_RAIL_CURVED_ZP_XP: { - Vector3d Distance( - MinecartCollisionCallback.GetCollidedEntityPosition().x - GetPosX(), - 0, - MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() - ); + Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); - if (Distance.z == 0.) - { - Distance.z = 0.0001; - } + Distance.z = std::max(Distance.z, 0.001); - if (((Distance.z >= 0) && ((Distance.x / Distance.z) >= 1)) || - ((Distance.z<0) && ((Distance.x / Distance.z) <= 1))) + if ( + ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || + ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) + ) { if ((-GetSpeedX() * 0.4) < 0.01) { - AddSpeedX( -4/sqrt(2) ); - AddSpeedZ( 4/sqrt(2) ); + AddSpeedX(-4/sqrt(2)); + AddSpeedZ(4/sqrt(2)); } else { - SetSpeedX( -GetSpeedX() * 0.4 ); - SetSpeedZ( GetSpeedZ() * 0.4 ); + SetSpeedX(-GetSpeedX() * 0.4); + SetSpeedZ(GetSpeedZ() * 0.4); } } else if ((GetSpeedX() * 0.4) < 0.01) { - AddSpeedX( 4/sqrt(2) ); - AddSpeedZ( -4/sqrt(2) ); + AddSpeedX(4/sqrt(2)); + AddSpeedZ(-4/sqrt(2)); } else { - SetSpeedX( GetSpeedX() * 0.4 ); - SetSpeedZ( -GetSpeedZ() * 0.4 ); + SetSpeedX(GetSpeedX() * 0.4); + SetSpeedZ(-GetSpeedZ() * 0.4); } break; } case E_META_RAIL_CURVED_ZM_XP: case E_META_RAIL_CURVED_ZP_XM: { - Vector3d Distance( - MinecartCollisionCallback.GetCollidedEntityPosition().x - GetPosX(), - 0, - MinecartCollisionCallback.GetCollidedEntityPosition().z - GetPosZ() - ); + Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); - if (Distance.z == 0.) - { - Distance.z = 0.0001; - } + Distance.z = std::max(Distance.z, 0.001); - if (((Distance.z >= 0) && ((Distance.x / Distance.z) <= -1)) || - ((Distance.z<0) && ((Distance.x / Distance.z) >= -1))) + if ( + ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || + ((Distance.z < 0) && ((Distance.x / Distance.z) >= -1)) + ) { if ((GetSpeedX() * 0.4) < 0.01) { - AddSpeedX( 4/sqrt(2) ); - AddSpeedZ( 4/sqrt(2) ); + AddSpeedX(4/sqrt(2)); + AddSpeedZ(4/sqrt(2)); } else { - SetSpeedX( GetSpeedX() * 0.4 ); - SetSpeedZ( GetSpeedZ() * 0.4 ); + SetSpeedX(GetSpeedX() * 0.4); + SetSpeedZ(GetSpeedZ() * 0.4); } } else if ((-GetSpeedX() * 0.4) < 0.01) { - AddSpeedX( -4/sqrt(2) ); - AddSpeedZ( -4/sqrt(2) ); + AddSpeedX(-4/sqrt(2)); + AddSpeedZ(-4/sqrt(2)); } else { - SetSpeedX( -GetSpeedX() * 0.4 ); - SetSpeedZ( -GetSpeedZ() * 0.4 ); + SetSpeedX(-GetSpeedX() * 0.4); + SetSpeedZ(-GetSpeedZ() * 0.4); } break; } From 3a7089539cc6be6e4ed00e17497e0dd327b9d67b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 14 Aug 2014 23:06:46 +0200 Subject: [PATCH 028/102] RankMgr: Removed unneeded testing code. --- src/RankManager.cpp | 210 +------------------------------------------- 1 file changed, 2 insertions(+), 208 deletions(-) diff --git a/src/RankManager.cpp b/src/RankManager.cpp index e64a47eb6..96c4baa56 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -12,215 +12,9 @@ -/* -// This code is for internal testing while developing the cRankManager class -static class cRankMgrTest -{ -public: - cRankMgrTest(void) : - m_Mgr() - { - // Initialize logging: - new cMCLogger(); - AString UUID = "b1caf24202a841a78055a079c460eee7"; // UUID for "xoft" - LOG("Testing UUID %s", UUID.c_str()); - - // Test the initial state of the ranks: - LOG("Initial test:"); - ReportPlayer(UUID); - - // Add a rank, a few groups and permissions and set the player to use them: - LOG("Adding data..."); - m_Mgr.AddRank("TestRank1", "[test]", "[/test]", "7"); - m_Mgr.AddRank("TestRank2", "[t2]", "[/t2]", "8"); - m_Mgr.AddGroup("TestGroup1"); - m_Mgr.AddGroup("TestGroup2"); - m_Mgr.AddGroupToRank("TestGroup1", "TestRank1"); - m_Mgr.AddGroupToRank("TestGroup2", "TestRank1"); - m_Mgr.AddGroupToRank("TestGroup2", "TestRank2"); - m_Mgr.AddPermissionToGroup("testpermission1.1", "TestGroup1"); - m_Mgr.AddPermissionToGroup("testpermission1.2", "TestGroup1"); - m_Mgr.AddPermissionToGroup("testpermission1.3", "TestGroup1"); - m_Mgr.AddPermissionToGroup("common", "TestGroup1"); - m_Mgr.AddPermissionToGroup("testpermission2.1", "TestGroup2"); - m_Mgr.AddPermissionToGroup("common", "TestGroup2"); - m_Mgr.SetPlayerRank(UUID, "xoft", "TestRank1"); - - // Test the added data: - LOG("Testing the added data:"); - LOG("IsGroupInRank(TestGroup1, TestRank1) = %s", m_Mgr.IsGroupInRank("TestGroup1", "TestRank1") ? "true" : "false"); - LOG("IsGroupInRank(TestGroup3, TestRank1) = %s", m_Mgr.IsGroupInRank("TestGroup3", "TestRank1") ? "true" : "false"); - LOG("IsPermissionInGroup(testpermission1.2, TestGroup1) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup1") ? "true" : "false"); // Existing permission, in group - LOG("IsPermissionInGroup(testpermission1.2, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.2", "TestGroup2") ? "true" : "false"); // Existing permission, not in group - LOG("IsPermissionInGroup(testpermission1.9, TestGroup2) = %s", m_Mgr.IsPermissionInGroup("testpermission1.9", "TestGroup2") ? "true" : "false"); // Non-existing permission - LOG("IsPlayerRankSet(%s) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID) ? "true" : "false"); - LOG("IsPlayerRankSet(%s1) = %s", UUID.c_str(), m_Mgr.IsPlayerRankSet(UUID + "1") ? "true" : "false"); - LOG("GroupExists(TestGroup1) = %s", m_Mgr.GroupExists("TestGroup1") ? "true" : "false"); - LOG("GroupExists(TestGroup3) = %s", m_Mgr.GroupExists("TestGroup3") ? "true" : "false"); - LOG("RankExists(TestRank1) = %s", m_Mgr.RankExists("TestRank1") ? "true" : "false"); - LOG("RankExists(NonexistentRank) = %s", m_Mgr.RankExists("NonexistentRank") ? "true" : "false"); - ReportRankGroups("TestRank1"); - ReportRankGroups("NonexistentRank"); - ReportGroupPermissions("TestGroup1"); - ReportGroupPermissions("NonexistentGroup"); - - // Report the contents of the DB: - ReportAll(); - - // Test the assignments above: - LOG("After-assignment test:"); - ReportPlayer(UUID); - - // Test removing a permission from a group: - LOG("Removing permission testpermission1.3 from group TestGroup1."); - m_Mgr.RemovePermissionFromGroup("testpermission1.3", "TestGroup1"); - ReportGroupPermissions("TestGroup1"); - LOG("Removing permission common from group TestGroup1."); - m_Mgr.RemovePermissionFromGroup("common", "TestGroup1"); - ReportGroupPermissions("TestGroup1"); // Check that it's not present - ReportGroupPermissions("TestGroup2"); // Check that it's still present here - - // Test removing a group from rank: - LOG("Removing group TestGroup2 from rank TestRank1."); - m_Mgr.RemoveGroupFromRank("TestGroup2", "TestRank1"); - ReportRankGroups("TestRank1"); - LOG("Removing group TestGroup3 from rank TestRank1."); - m_Mgr.RemoveGroupFromRank("TestGroup3", "TestRank1"); - ReportRankGroups("TestRank1"); - - // Test re-adding the groups: - LOG("Re-adding groups to TestRank1."); - m_Mgr.AddGroupToRank("TestGroup1", "TestRank1"); - m_Mgr.AddGroupToRank("TestGroup2", "TestRank1"); - ReportRankGroups("TestRank1"); - - // Test removing a group altogether: - LOG("Removing group TestGroup2"); - m_Mgr.RemoveGroup("TestGroup2"); - ReportAll(); - - // Test removing a rank: - LOG("Removing rank TestRank2, replacing with rank TestRank1."); - m_Mgr.RemoveRank("TestRank2", "TestRank1"); - ReportAll(); - LOG("Removing rank Test altogether."); - m_Mgr.RemoveRank("Test", ""); - ReportAll(); - - // Test renaming a rank: - LOG("Renaming rank TestRank1 to Test"); - m_Mgr.RenameRank("TestRank1", "Test"); - ReportRankGroups("TestRank1"); - ReportRankGroups("Test"); - LOG("Player after renaming:"); - ReportPlayer(UUID); - - // Test renaming a group: - LOG("Renaming group TestGroup1 to Test"); - m_Mgr.RenameGroup("TestGroup1", "Test"); - ReportGroupPermissions("TestGroup1"); - ReportGroupPermissions("Test"); - LOG("Player after renaming:"); - ReportPlayer(UUID); - m_Mgr.RenameGroup("Test", "TestGroup1"); - - // Test removing the rank in favor of another one: - m_Mgr.RemoveRank("Test", "TestRank2"); - LOG("After-removal test:"); - ReportPlayer(UUID); - - LOG("Done."); - } - - - void ReportAll(void) - { - // Report all ranks: - AStringVector Ranks = m_Mgr.GetAllRanks(); - LOG("All ranks (%u):", (unsigned)Ranks.size()); - for (AStringVector::const_iterator itr = Ranks.begin(), end = Ranks.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - - // Report all groups: - AStringVector Groups = m_Mgr.GetAllGroups(); - LOG("All groups (%u):", (unsigned)Groups.size()); - for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - - // Report all permissions: - AStringVector Permissions = m_Mgr.GetAllPermissions(); - LOG("All permissions (%u):", (unsigned)Permissions.size()); - for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - } - - - void ReportPlayer(const AString & a_PlayerUUID) - { - // Get the player's UUID and rank: - LOG(" Rank: '%s'", m_Mgr.GetPlayerRankName(a_PlayerUUID).c_str()); - - // List all the permission groups for the player: - AStringVector Groups = m_Mgr.GetPlayerGroups(a_PlayerUUID); - LOG(" Groups (%u):", (unsigned)Groups.size()); - for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) - { - LOG(" '%s'" , itr->c_str()); - } // for itr - Groups[] - - // List all the permissions for the player: - AStringVector Permissions = m_Mgr.GetPlayerPermissions(a_PlayerUUID); - LOG(" Permissions (%u):", (unsigned)Permissions.size()); - for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } // for itr - Groups[] - } - - - void ReportRankGroups(const AString & a_RankName) - { - AStringVector Groups = m_Mgr.GetRankGroups(a_RankName); - LOG("Groups in rank %s: %u", a_RankName.c_str(), (unsigned)Groups.size()); - for (AStringVector::const_iterator itr = Groups.begin(), end = Groups.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - AStringVector Permissions = m_Mgr.GetRankPermissions(a_RankName); - LOG("Permissions in rank %s: %u", a_RankName.c_str(), (unsigned)Permissions.size()); - for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - } - - - void ReportGroupPermissions(const AString & a_GroupName) - { - AStringVector Permissions = m_Mgr.GetGroupPermissions(a_GroupName); - LOG("Permissions in group %s: %u", a_GroupName.c_str(), (unsigned)Permissions.size()); - for (AStringVector::const_iterator itr = Permissions.begin(), end = Permissions.end(); itr != end; ++itr) - { - LOG(" '%s'", itr->c_str()); - } - } - -protected: - cRankManager m_Mgr; -} g_RankMgrTest; -//*/ - - - - - //////////////////////////////////////////////////////////////////////////////// +// cRankManagerIniMigrator: + /** Migrates from groups.ini and users.ini into the rankmanager DB */ class cRankManagerIniMigrator { From 0f631febfc3f670e8e9eb60ec4f89659ad7d0c71 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Fri, 15 Aug 2014 13:40:56 +0200 Subject: [PATCH 029/102] Add some comments --- src/Entities/Minecart.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 8e11d8a07..0455c9ab3 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -875,17 +875,23 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); + // Prevent division by small numbers Distance.z = std::max(Distance.z, 0.001); + /* Check to which side the minecart is to be pushed. + Let's consider a z-x-coordinate system where the minecart is the center (0/0). + The minecart moves along the line z = -x, the perpendicular line to this is z = x. + In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. + */ if ( ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) ) { - if ((-GetSpeedX() * 0.4) < 0.01) + if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) { - AddSpeedX(-4/sqrt(2)); - AddSpeedZ(4/sqrt(2)); + AddSpeedX(-4 / sqrt(2)); + AddSpeedZ(4 / sqrt(2)); } else { @@ -893,10 +899,10 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) SetSpeedZ(GetSpeedZ() * 0.4); } } - else if ((GetSpeedX() * 0.4) < 0.01) + else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) { - AddSpeedX(4/sqrt(2)); - AddSpeedZ(-4/sqrt(2)); + AddSpeedX(4 / sqrt(2)); + AddSpeedZ(-4 / sqrt(2)); } else { @@ -910,8 +916,13 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); + // Prevent division by small numbers Distance.z = std::max(Distance.z, 0.001); + /* Check to which side the minecart is to be pushed. + Let's consider a z-x-coordinate system where the minecart is the center (0/0). + The minecart moves along the line z = x, the perpendicular line to this is z = -x. + In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ if ( ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) >= -1)) @@ -919,8 +930,8 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { if ((GetSpeedX() * 0.4) < 0.01) { - AddSpeedX(4/sqrt(2)); - AddSpeedZ(4/sqrt(2)); + AddSpeedX(4 / sqrt(2)); + AddSpeedZ(4 / sqrt(2)); } else { @@ -930,8 +941,8 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) } else if ((-GetSpeedX() * 0.4) < 0.01) { - AddSpeedX(-4/sqrt(2)); - AddSpeedZ(-4/sqrt(2)); + AddSpeedX(-4 / sqrt(2)); + AddSpeedZ(-4 / sqrt(2)); } else { From be03b84048a49e04db11aa6ce80b3d18fff313b1 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Fri, 15 Aug 2014 13:43:45 +0200 Subject: [PATCH 030/102] End of comment moved away from new line --- src/Entities/Minecart.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 0455c9ab3..f190d972e 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -881,8 +881,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) /* Check to which side the minecart is to be pushed. Let's consider a z-x-coordinate system where the minecart is the center (0/0). The minecart moves along the line z = -x, the perpendicular line to this is z = x. - In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. - */ + In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ if ( ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) From c473d8cfb82009411f5a3977b7041ee49ba08003 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Fri, 15 Aug 2014 14:00:51 +0200 Subject: [PATCH 031/102] Clarify comment message --- src/Entities/Minecart.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index f190d972e..4753f720d 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -880,7 +880,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) /* Check to which side the minecart is to be pushed. Let's consider a z-x-coordinate system where the minecart is the center (0/0). - The minecart moves along the line z = -x, the perpendicular line to this is z = x. + The minecart moves along the line x = -z, the perpendicular line to this is x = z. In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ if ( ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || @@ -920,7 +920,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) /* Check to which side the minecart is to be pushed. Let's consider a z-x-coordinate system where the minecart is the center (0/0). - The minecart moves along the line z = x, the perpendicular line to this is z = -x. + The minecart moves along the line x = z, the perpendicular line to this is x = -z. In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ if ( ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || From 72c02ceb171949acd07338e77c8ee0d3439f8173 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Fri, 15 Aug 2014 17:54:43 +0200 Subject: [PATCH 032/102] Added a lot of comments --- src/Entities/Minecart.cpp | 66 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 4753f720d..9420eca02 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -876,7 +876,10 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); // Prevent division by small numbers - Distance.z = std::max(Distance.z, 0.001); + if (abs(Distance.z) < 0.001) + { + Distance.z = 0.001; + } /* Check to which side the minecart is to be pushed. Let's consider a z-x-coordinate system where the minecart is the center (0/0). @@ -886,27 +889,27 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) ) - { - if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) - { + { // Moving -X + Z + if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) // ~ speedX >= 0 + { // Immobile or not moving in the "right" direction. Give it a bump! AddSpeedX(-4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } - else - { - SetSpeedX(-GetSpeedX() * 0.4); - SetSpeedZ(GetSpeedZ() * 0.4); + else // ~ SpeedX < 0 + { // Moving in the "right" direction. Only accelerate it a bit. + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } - } - else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) - { + } // Moving +X -Z + else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) // ~ SpeedX <= 0 + { // Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } - else - { - SetSpeedX(GetSpeedX() * 0.4); - SetSpeedZ(-GetSpeedZ() * 0.4); + else // ~ SpeedX > 0 + { // Moving in the "right" direction + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } break; } @@ -916,37 +919,40 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ()); // Prevent division by small numbers - Distance.z = std::max(Distance.z, 0.001); + if (abs(Distance.z) < 0.001) + { + Distance.z = 0.001; + } /* Check to which side the minecart is to be pushed. Let's consider a z-x-coordinate system where the minecart is the center (0/0). The minecart moves along the line x = z, the perpendicular line to this is x = -z. In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ - if ( + if ( // Moving +X +Z ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) >= -1)) ) { - if ((GetSpeedX() * 0.4) < 0.01) - { + if ((GetSpeedX() * 0.4) < 0.01) // ~ SpeedX <= 0 + { // Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } - else - { - SetSpeedX(GetSpeedX() * 0.4); - SetSpeedZ(GetSpeedZ() * 0.4); + else // SpeedX > 0 + { // Moving in the "right" direction + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } - } - else if ((-GetSpeedX() * 0.4) < 0.01) - { + } // Moving -X -Z + else if ((-GetSpeedX() * 0.4) < 0.01) // ~ SpeedX >= 0 + { // Immobile or not moving in the "right" direction AddSpeedX(-4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } - else - { - SetSpeedX(-GetSpeedX() * 0.4); - SetSpeedZ(-GetSpeedZ() * 0.4); + else // ~ SpeedX < 0 + { // Moving in the "right" direction + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } break; } From c70886a7124e5940b67cb4f1b4593f103f2707d8 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Mon, 18 Aug 2014 01:57:44 +0200 Subject: [PATCH 033/102] Adjust comment formatting --- src/Entities/Minecart.cpp | 60 ++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 9420eca02..13469edb3 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -889,25 +889,35 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) ) - { // Moving -X + Z - if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) // ~ speedX >= 0 - { // Immobile or not moving in the "right" direction. Give it a bump! + // Moving -X +Z + { + if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) + // ~ speedX >= 0 + { + // Immobile or not moving in the "right" direction. Give it a bump! AddSpeedX(-4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } - else // ~ SpeedX < 0 - { // Moving in the "right" direction. Only accelerate it a bit. + else + // ~ SpeedX < 0 + { + // Moving in the "right" direction. Only accelerate it a bit. SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } - } // Moving +X -Z - else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) // ~ SpeedX <= 0 - { // Immobile or not moving in the "right" direction + } + else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) + // Moving +X -Z + // ~ SpeedX <= 0 + { + // Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } - else // ~ SpeedX > 0 - { // Moving in the "right" direction + else + // ~ SpeedX > 0 + { + // Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } @@ -928,29 +938,39 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) Let's consider a z-x-coordinate system where the minecart is the center (0/0). The minecart moves along the line x = z, the perpendicular line to this is x = -z. In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */ - if ( // Moving +X +Z + if ( ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) >= -1)) ) + // Moving +X +Z { - if ((GetSpeedX() * 0.4) < 0.01) // ~ SpeedX <= 0 - { // Immobile or not moving in the "right" direction + if ((GetSpeedX() * 0.4) < 0.01) + // ~ SpeedX <= 0 + { + // Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } - else // SpeedX > 0 - { // Moving in the "right" direction + else + // SpeedX > 0 + { + // Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } - } // Moving -X -Z - else if ((-GetSpeedX() * 0.4) < 0.01) // ~ SpeedX >= 0 - { // Immobile or not moving in the "right" direction + } + else if ((-GetSpeedX() * 0.4) < 0.01) + // Moving -X -Z + // ~ SpeedX >= 0 + { + // Immobile or not moving in the "right" direction AddSpeedX(-4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } - else // ~ SpeedX < 0 - { // Moving in the "right" direction + else + // ~ SpeedX < 0 + { + // Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } From 949aa2f3836cfa2b64ab5104b4b4103c4e2ad537 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 19 Aug 2014 17:34:11 +0200 Subject: [PATCH 034/102] cPlayer reads ranks from cRankManager. --- src/Bindings/ManualBindings.cpp | 99 ++++++------ src/Entities/Player.cpp | 260 +++++++------------------------- src/Entities/Player.h | 53 ++++--- 3 files changed, 144 insertions(+), 268 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index c8eb5d138..a60408910 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -1803,49 +1803,30 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) -static int tolua_cPlayer_GetGroups(lua_State * tolua_S) +static int tolua_cPlayer_GetPermissions(lua_State * tolua_S) { + // Function signature: cPlayer:GetPermissions() -> {permissions-array} + + // Check the params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPlayer") || + !L.CheckParamEnd (2) + ) + { + return 0; + } + + // Get the params: cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); - - const cPlayer::GroupList & AllGroups = self->GetGroups(); - - lua_createtable(tolua_S, (int)AllGroups.size(), 0); - int newTable = lua_gettop(tolua_S); - int index = 1; - cPlayer::GroupList::const_iterator iter = AllGroups.begin(); - while (iter != AllGroups.end()) + if (self == NULL) { - const cGroup * Group = *iter; - tolua_pushusertype(tolua_S, (void *)Group, "const cGroup"); - lua_rawseti(tolua_S, newTable, index); - ++iter; - ++index; - } - return 1; -} - - - - - -static int tolua_cPlayer_GetResolvedPermissions(lua_State * tolua_S) -{ - cPlayer * self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); - - cPlayer::StringList AllPermissions = self->GetResolvedPermissions(); - - lua_createtable(tolua_S, (int)AllPermissions.size(), 0); - int newTable = lua_gettop(tolua_S); - int index = 1; - cPlayer::StringList::iterator iter = AllPermissions.begin(); - while (iter != AllPermissions.end()) - { - std::string & Permission = *iter; - lua_pushlstring(tolua_S, Permission.c_str(), Permission.length()); - lua_rawseti(tolua_S, newTable, index); - ++iter; - ++index; + LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); + return 0; } + + // Push the permissions: + L.Push(self->GetPermissions()); return 1; } @@ -1902,6 +1883,40 @@ static int tolua_cPlayer_OpenWindow(lua_State * tolua_S) +static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S) +{ + // Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool + + // Check the params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPlayer") || + !L.CheckParamString (2, 3) || + !L.CheckParamEnd (4) + ) + { + return 0; + } + + // Get the params: + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); + if (self == NULL) + { + LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); + return 0; + } + AString Permission, Template; + L.GetStackValues(2, Permission, Template); + + // Push the result of the match: + L.Push(self->PermissionMatches(StringSplit(Permission, "."), StringSplit(Template, "."))); + return 1; +} + + + + + template < class OBJTYPE, void (OBJTYPE::*SetCallback)(cPluginLua * a_Plugin, int a_FnRef) @@ -3295,9 +3310,9 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlayer"); - tolua_function(tolua_S, "GetGroups", tolua_cPlayer_GetGroups); - tolua_function(tolua_S, "GetResolvedPermissions", tolua_cPlayer_GetResolvedPermissions); - tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow); + tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions); + tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow); + tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cLuaWindow"); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 4398a5bf3..423ca3317 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -59,7 +59,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : m_EnderChestContents(9, 3), m_CurrentWindow(NULL), m_InventoryWindow(NULL), - m_Color('-'), m_GameMode(eGameMode_NotSet), m_IP(""), m_ClientHandle(a_Client), @@ -1359,48 +1358,6 @@ void cPlayer::SetVisible(bool a_bVisible) -void cPlayer::AddToGroup( const AString & a_GroupName) -{ - cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName); - m_Groups.push_back( Group); - LOGD("Added %s to group %s", GetName().c_str(), a_GroupName.c_str()); - ResolveGroups(); - ResolvePermissions(); -} - - - - - -void cPlayer::RemoveFromGroup( const AString & a_GroupName) -{ - bool bRemoved = false; - for (GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr) - { - if ((*itr)->GetName().compare(a_GroupName) == 0) - { - m_Groups.erase( itr); - bRemoved = true; - break; - } - } - - if (bRemoved) - { - LOGD("Removed %s from group %s", GetName().c_str(), a_GroupName.c_str()); - ResolveGroups(); - ResolvePermissions(); - } - else - { - LOGWARN("Tried to remove %s from group %s but was not in that group", GetName().c_str(), a_GroupName.c_str()); - } -} - - - - - bool cPlayer::HasPermission(const AString & a_Permission) { if (a_Permission.empty()) @@ -1409,47 +1366,18 @@ bool cPlayer::HasPermission(const AString & a_Permission) return true; } - AStringVector Split = StringSplit( a_Permission, "."); - PermissionMap Possibilities = m_ResolvedPermissions; - // Now search the namespaces - while (Possibilities.begin() != Possibilities.end()) + AStringVector Split = StringSplit(a_Permission, "."); + + // Iterate over all granted permissions; if any matches, then return success: + for (AStringVectorVector::const_iterator itr = m_SplitPermissions.begin(), end = m_SplitPermissions.end(); itr != end; ++itr) { - PermissionMap::iterator itr = Possibilities.begin(); - if (itr->second) + if (PermissionMatches(Split, *itr)) { - AStringVector OtherSplit = StringSplit( itr->first, "."); - if (OtherSplit.size() <= Split.size()) - { - unsigned int i; - for (i = 0; i < OtherSplit.size(); ++i) - { - if (OtherSplit[i].compare( Split[i]) != 0) - { - if (OtherSplit[i].compare("*") == 0) return true; // WildCard man!! WildCard! - break; - } - } - if (i == Split.size()) return true; - } - } - Possibilities.erase( itr); - } - - // Nothing that matched :( - return false; -} - - - - - -bool cPlayer::IsInGroup( const AString & a_Group) -{ - for (GroupList::iterator itr = m_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr) - { - if (a_Group.compare( (*itr)->GetName().c_str()) == 0) return true; - } + } + } // for itr - m_SplitPermissions[] + + // No granted permission matches return false; } @@ -1457,68 +1385,35 @@ bool cPlayer::IsInGroup( const AString & a_Group) -void cPlayer::ResolvePermissions() +bool cPlayer::PermissionMatches(const AStringVector & a_Permission, const AStringVector & a_Template) { - m_ResolvedPermissions.clear(); // Start with an empty map - - // Copy all player specific permissions into the resolved permissions map - for (PermissionMap::iterator itr = m_Permissions.begin(); itr != m_Permissions.end(); ++itr) + // Check the sub-items if they are the same or there's a wildcard: + size_t lenP = a_Permission.size(); + size_t lenT = a_Template.size(); + size_t minLen = std::min(lenP, lenT); + for (size_t i = 0; i < minLen; i++) { - m_ResolvedPermissions[ itr->first ] = itr->second; - } - - for (GroupList::iterator GroupItr = m_ResolvedGroups.begin(); GroupItr != m_ResolvedGroups.end(); ++GroupItr) - { - const cGroup::PermissionMap & Permissions = (*GroupItr)->GetPermissions(); - for (cGroup::PermissionMap::const_iterator itr = Permissions.begin(); itr != Permissions.end(); ++itr) + if (a_Template[i] == "*") { - m_ResolvedPermissions[ itr->first ] = itr->second; + // Has matched so far and now there's a wildcard in the template, so the permission matches: + return true; + } + if (a_Permission[i] != a_Template[i]) + { + // Found a mismatch + return false; } } -} - - - - -void cPlayer::ResolveGroups() -{ - // Clear resolved groups first - m_ResolvedGroups.clear(); - - // Get a complete resolved list of all groups the player is in - std::map< cGroup*, bool > AllGroups; // Use a map, because it's faster than iterating through a list to find duplicates - GroupList ToIterate; - for (GroupList::iterator GroupItr = m_Groups.begin(); GroupItr != m_Groups.end(); ++GroupItr) + // So far all the sub-items have matched + // If the sub-item count is the same, then the permission matches: + if (lenP == lenT) { - ToIterate.push_back( *GroupItr); - } - while (ToIterate.begin() != ToIterate.end()) - { - cGroup* CurrentGroup = *ToIterate.begin(); - if (AllGroups.find( CurrentGroup) != AllGroups.end()) - { - LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!", - GetName().c_str(), CurrentGroup->GetName().c_str() - ); - } - else - { - AllGroups[ CurrentGroup ] = true; - m_ResolvedGroups.push_back( CurrentGroup); // Add group to resolved list - const cGroup::GroupList & Inherits = CurrentGroup->GetInherits(); - for (cGroup::GroupList::const_iterator itr = Inherits.begin(); itr != Inherits.end(); ++itr) - { - if (AllGroups.find( *itr) != AllGroups.end()) - { - LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", GetName().c_str(), (*itr)->GetName().c_str()); - continue; - } - ToIterate.push_back( *itr); - } - } - ToIterate.erase( ToIterate.begin()); + return true; } + + // There are more sub-items in either the permission or the template, not a match: + return false; } @@ -1527,17 +1422,14 @@ void cPlayer::ResolveGroups() AString cPlayer::GetColor(void) const { - if (m_Color != '-') + if (m_MsgNameColorCode.empty() || (m_MsgNameColorCode == "-")) { - return cChatColor::Delimiter + m_Color; + // Color has not been assigned, return an empty string: + return AString(); } - if (m_Groups.size() < 1) - { - return cChatColor::White; - } - - return (*m_Groups.begin())->GetColor(); + // Return the color, including the delimiter: + return cChatColor::Delimiter + m_MsgNameColorCode; } @@ -1653,48 +1545,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) -void cPlayer::LoadPermissionsFromDisk() -{ - m_Groups.clear(); - m_Permissions.clear(); - - cIniFile IniFile; - if (IniFile.ReadFile("users.ini")) - { - AString Groups = IniFile.GetValueSet(GetName(), "Groups", "Default"); - AStringVector Split = StringSplitAndTrim(Groups, ","); - - for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) - { - if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr)) - { - LOGWARNING("The group %s for player %s was not found!", itr->c_str(), GetName().c_str()); - } - AddToGroup(*itr); - } - - AString Color = IniFile.GetValue(GetName(), "Color", "-"); - if (!Color.empty()) - { - m_Color = Color[0]; - } - } - else - { - cGroupManager::GenerateDefaultUsersIni(IniFile); - IniFile.AddValue("Groups", GetName(), "Default"); - AddToGroup("Default"); - } - IniFile.WriteFile("users.ini"); - ResolvePermissions(); -} - - - - bool cPlayer::LoadFromDisk(cWorldPtr & a_World) { - LoadPermissionsFromDisk(); + LoadRank(); // Load from the UUID file: if (LoadFromFile(GetUUIDFileName(m_UUID), a_World)) @@ -1928,26 +1781,6 @@ bool cPlayer::SaveToDisk() -cPlayer::StringList cPlayer::GetResolvedPermissions() -{ - StringList Permissions; - - const PermissionMap& ResolvedPermissions = m_ResolvedPermissions; - for (PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr) - { - if (itr->second) - { - Permissions.push_back( itr->first); - } - } - - return Permissions; -} - - - - - void cPlayer::UseEquippedItem(int a_Amount) { if (IsGameModeCreative()) // No damage in creative @@ -2206,6 +2039,27 @@ void cPlayer::ApplyFoodExhaustionFromMovement() +void cPlayer::LoadRank(void) +{ + // Load the values from cRankManager: + cRankManager & RankMgr = cRoot::Get()->GetRankManager(); + m_Rank = RankMgr.GetPlayerRankName(m_UUID); + m_Permissions = RankMgr.GetPlayerPermissions(m_UUID); + RankMgr.GetPlayerMsgVisuals(m_UUID, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); + + // Break up the individual permissions on each dot, into m_SplitPermissions: + m_SplitPermissions.clear(); + m_SplitPermissions.reserve(m_Permissions.size()); + for (AStringVector::const_iterator itr = m_Permissions.begin(), end = m_Permissions.end(); itr != end; ++itr) + { + m_SplitPermissions.push_back(StringSplit(*itr, ".")); + } // for itr - m_Permissions[] +} + + + + + void cPlayer::Detach() { super::Detach(); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index d3ed1ef9d..0ae014eeb 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -236,24 +236,20 @@ public: // tolua_end - typedef std::list< cGroup* > GroupList; - typedef std::list< std::string > StringList; + bool HasPermission(const AString & a_Permission); // tolua_export - /** Adds a player to existing group or creates a new group when it doesn't exist */ - void AddToGroup( const AString & a_GroupName); // tolua_export - - /** Removes a player from the group, resolves permissions and group inheritance (case sensitive) */ - void RemoveFromGroup( const AString & a_GroupName); // tolua_export - - bool HasPermission( const AString & a_Permission); // tolua_export - const GroupList & GetGroups() { return m_Groups; } // >> EXPORTED IN MANUALBINDINGS << - StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS << - bool IsInGroup( const AString & a_Group); // tolua_export + /** Returns true iff a_Permission matches the a_Template. + A match is defined by either being exactly the same, or each sub-item matches until there's a wildcard in a_Template. + Ie. {"a", "b", "c"} matches {"a", "b", "*"} but doesn't match {"a", "b"} */ + static bool PermissionMatches(const AStringVector & a_Permission, const AStringVector & a_Template); // Exported in ManualBindings with AString params + + /** Returns all the permissions that the player has assigned to them. */ + const AStringVector & GetPermissions(void) { return m_Permissions; } // Exported in ManualBindings.cpp // tolua_begin - /** Returns the full color code to use for this player, based on their primary group or set in m_Color. - The returned value includes the cChatColor::Delimiter. */ + /** Returns the full color code to use for this player, based on their rank. + The returned value either is empty, or includes the cChatColor::Delimiter. */ AString GetColor(void) const; /** tosses the item in the selected hotbar slot */ @@ -347,8 +343,6 @@ public: */ bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); - void LoadPermissionsFromDisk(void); // tolua_export - const AString & GetLoadedWorldName() { return m_LoadedWorldName; } void UseEquippedItem(int a_Amount = 1); @@ -424,6 +418,11 @@ public: // tolua_end + /** (Re)loads the rank and permissions from the cRankManager. + Expects the m_UUID member to be valid. + Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */ + void LoadRank(void); + // cEntity overrides: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } @@ -432,12 +431,22 @@ public: virtual void Detach(void); protected: - typedef std::map< std::string, bool > PermissionMap; - PermissionMap m_ResolvedPermissions; - PermissionMap m_Permissions; - GroupList m_ResolvedGroups; - GroupList m_Groups; + typedef std::vector > AStringVectorVector; + + /** The name of the rank assigned to this player. */ + AString m_Rank; + + /** All the permissions that this player has, based on their rank. */ + AStringVector m_Permissions; + + /** All the permissions that this player has, based on their rank, split into individual dot-delimited parts. + This is used mainly by the HasPermission() function to optimize the lookup. */ + AStringVectorVector m_SplitPermissions; + + // Message visuals: + AString m_MsgPrefix, m_MsgSuffix; + AString m_MsgNameColorCode; AString m_PlayerName; AString m_LoadedWorldName; @@ -482,8 +491,6 @@ protected: /** The player's last saved bed position */ Vector3i m_LastBedPos; - char m_Color; - eGameMode m_GameMode; AString m_IP; From 81979419ad175c98d462ef58cdd39c7c609cd7c5 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 17:56:30 +0200 Subject: [PATCH 035/102] RankMgr: Fixed an ignored return value in the API. --- src/Bindings/ManualBindings_RankManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index b109b0097..be8ad12c8 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -83,8 +83,8 @@ static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) S.GetStackValues(2, Permission, GroupName); // Add the group to the rank: - cRoot::Get()->GetRankManager().AddPermissionToGroup(Permission, GroupName); - return 0; + S.Push(cRoot::Get()->GetRankManager().AddPermissionToGroup(Permission, GroupName)); + return 1; } From 15a20b1d2aa1229c75bd626af46a0a968aefff96 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 18:09:13 +0200 Subject: [PATCH 036/102] RankMgr bindings: fixed GetRankVisuals return value. --- src/Bindings/ManualBindings_RankManager.cpp | 76 +++++++++++---------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index be8ad12c8..bc31ea687 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -399,41 +399,6 @@ static int tolua_cRankManager_GetRankGroups(lua_State * L) -/** Binds cRankManager::GetRankVisuals */ -static int tolua_cRankManager_GetRankVisuals(lua_State * L) -{ - // function signature: - // cRankManager:GetRankVisuals(RankName) -> MsgPrefix, MsgSuffix, MsgNameColorCode - - cLuaState S(L); - if ( - !S.CheckParamUserTable(1, "cRankManager") || - !S.CheckParamString(2) || - !S.CheckParamEnd(3) - ) - { - return 0; - } - - // Get the params: - AString RankName; - S.GetStackValue(2, RankName); - - // Get the visuals: - AString MsgPrefix, MsgSuffix, MsgNameColorCode; - cRoot::Get()->GetRankManager().GetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode); - - // Push the results: - S.Push(MsgPrefix); - S.Push(MsgSuffix); - S.Push(MsgNameColorCode); - return 3; -} - - - - - /** Binds cRankManager::GetRankPermissions */ static int tolua_cRankManager_GetRankPermissions(lua_State * L) { @@ -466,6 +431,45 @@ static int tolua_cRankManager_GetRankPermissions(lua_State * L) +/** Binds cRankManager::GetRankVisuals */ +static int tolua_cRankManager_GetRankVisuals(lua_State * L) +{ + // function signature: + // cRankManager:GetRankVisuals(RankName) -> MsgPrefix, MsgSuffix, MsgNameColorCode + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the visuals: + AString MsgPrefix, MsgSuffix, MsgNameColorCode; + if (!cRoot::Get()->GetRankManager().GetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode)) + { + // No such rank, return nothing: + return 0; + } + + // Push the results: + S.Push(MsgPrefix); + S.Push(MsgSuffix); + S.Push(MsgNameColorCode); + return 3; +} + + + + + /** Binds cRankManager::GroupExists */ static int tolua_cRankManager_GroupExists(lua_State * L) { @@ -886,8 +890,8 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); - tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); + tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); tolua_function(tolua_S, "GroupExists", tolua_cRankManager_GroupExists); tolua_function(tolua_S, "IsGroupInRank", tolua_cRankManager_IsGroupInRank); tolua_function(tolua_S, "IsPermissionInGroup", tolua_cRankManager_IsPermissionInGroup); From 9f8eee578cf2834de8221cecb2c753a06a912739 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 19:09:45 +0200 Subject: [PATCH 037/102] APIDump: Added cRankManager documentation. --- MCServer/Plugins/APIDump/APIDesc.lua | 56 ++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 64ba80c5f..ce3303087 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2004,6 +2004,62 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); }, }, -- cPluginManager + cRankManager = + { + Desc = [[ + Manages the players' permissions. The players are assigned a single rank, which contains groups of + permissions. The functions in this class query or modify these.

+

+ All the functions are static, call them using the cRankManager:Function() convention.

+

+ The players are identified by their UUID, to support player renaming.

+

+ The rank also contains specific "mesage visuals" - bits that are used for formatting messages from the + players. There's a message prefix, which is put in front of every message the player sends, and the + message suffix that is appended to each message. There's also a PlayerNameColorCode, which holds the + color that is used for the player's name in the messages.

+

+ Each rank can contain any number of permission groups. These groups allow for an easier setup of the + permissions - you can share groups among ranks, so the usual approach is to group similar permissions + together and add that group to any rank that should use those permissions.

+

+ Permissions are added to individual groups. Each group can support unlimited permissions. Note that + adding a permission to a group will make the permission available to all the ranks that contain that + permission group. + ]], + Functions = + { + AddGroup = { Params = "GroupName", Return = "", Notes = "Adds the group of the specified name. Logs a warning and does nothing if the group already exists." }, + AddGroupToRank = { Params = "GroupName, RankName", Return = "bool", Notes = "Adds the specified group to the specified rank. Returns true on success, false on failure - if the group name or the rank name is not found." }, + AddPermissionToGroup = { Params = "Permission, GroupName", Return = "bool", Notes = "Adds the specified permission to the specified group. Returns true on success, false on failure - if the group name is not found." }, + AddRank = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Adds a new rank of the specified name and with the specified message visuals. Logs an info message and does nothing if the rank already exists." }, + GetAllGroups = { Params = "", Return = "array-table of groups' names", Notes = "Returns an array-table containing the names of all the groups that are known to the manager." }, + GetAllPermissions = { Params = "", Return = "array-table of permissions", Notes = "Returns an array-table containing all the permissions that are known to the manager." }, + GetAllRanks = { Params = "", Return = "array-table of ranks' names", Notes = "Returns an array-table containing the names of all the ranks that are known to the manager." }, + GetGroupPermissions = { Params = "GroupName", Return = "array-table of permissions", Notes = "Returns an array-table containing the permissions that the specified group contains." }, + GetPlayerGroups = { Params = "PlayerUUID", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of the groups that are assigned to the specified player through their rank. Returns an empty table if the player is not known or has no rank or groups assigned to them." }, + GetPlayerMsgVisuals = { Params = "PlayerUUID", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals assigned to the player. If the player is not known or has no rank assigned, doesn't return any value." }, + GetPlayerPermissions = { Params = "PlayerUUID", Return = "array-table of permissions", Notes = "Returns the permissions that the specified player is assigned through their rank. Returns an empty table if the player is not known." }, + GetPlayerRankName = { Params = "PlayerUUID", Return = "RankName", Notes = "Returns the name of the rank that is assigned to the specified player. An empty string is returned if the player has no rank assigned to them." }, + GetRankGroups = { Params = "RankName", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of all the groups that are assigned to the specified rank. Returns an empty table if there is no such rank." }, + GetRankPermissions = { Params = "RankName", Return = "array-table of permissions", Notes = "Returns an array-table of all the permissions that are assigned to the specified rank through its groups. Returns an empty table if there is no such rank." }, + GetRankVisuals = { Params = "RankName", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals for the specified rank. Returns no value if the specified rank does not exist." }, + GroupExists = { Params = "GroupName", Return = "bool", Notes = "Returns true iff the specified group exists." }, + IsGroupInRank = { Params = "GroupName, RankName", Return = "bool", Notes = "Returns true iff the specified group is assigned to the specified rank." }, + IsPermissionInGroup = { Params = "Permission, GroupName", Return = "bool", Notes = "Returns true iff the specified permission is assigned to the specified group." }, + IsPlayerRankSet = { Params = "PlayerUUID", Return = "bool", Notes = "Returns true iff the specified player has a rank assigned to them." }, + RankExists = { Params = "RankName", Return = "bool", Notes = "Returns true iff the specified rank exists." }, + RemoveGroup = { Params = "GroupName", Return = "", Notes = "Removes the specified group completely. The group will be removed from all the ranks using it and then erased from the manager. Logs an info message and does nothing if the group doesn't exist." }, + RemoveGroupFromRank = { Params = "GroupName, RankName", Return = "", Notes = "Removes the specified group from the specified rank. The group will still exist, even if it isn't assigned to any rank. Logs an info message and does nothing if the group or rank doesn't exist." }, + RemovePermissionFromGroup = { Params = "Permission, GroupName", Return = "", Notes = "Removes the specified permission from the specified group. Logs an info message and does nothing if the group doesn't exist." }, + RemoveRank = { Params = "RankName, [ReplacementRankName]", Return = "", Notes = "Removes the specified rank. If ReplacementRankName is given, the players that have RankName will get their rank set to ReplacementRankName. If it isn't given, or is an invalid rank, the players will be removed from the manager, their ranks will be unset completely. Logs an info message and does nothing if the rank is not found." }, + RenameGroup = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified group. Logs an info message and does nothing if the group is not found." }, + RenameRank = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified rank. Logs an info message and does nothing if the rank is not found." }, + SetPlayerRank = { Params = "PlayerUUID, PlayerName, RankName", Return = "", Notes = "Updates the rank for the specified player. The player name is provided for reference, the UUID is used for identification. Logs a warning and does nothing if the rank is not found." }, + SetRankVisuals = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Updates the rank's message visuals. Logs an info message and does nothing if rank not found." }, + }, + }, -- cRankManager + cRoot = { Desc = [[ From 1b97e4e6ff202f63f5e6ae8a6130536be17b754a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 20:37:51 +0200 Subject: [PATCH 038/102] cPlayer: Exported the LoadRank function to Lua API. --- src/Entities/Player.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 0ae014eeb..bfafcb7fb 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -416,13 +416,13 @@ public: /** Returns the UUID (short format) that has been read from the client, or empty string if not available. */ const AString & GetUUID(void) const { return m_UUID; } - // tolua_end - /** (Re)loads the rank and permissions from the cRankManager. Expects the m_UUID member to be valid. Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */ void LoadRank(void); + // tolua_end + // cEntity overrides: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } From 2218f31cde5d04157469de0d5164059ffb8a6bca Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 22:21:41 +0200 Subject: [PATCH 039/102] Exported cServer:ShouldAuthenticate to Lua API. --- MCServer/Plugins/APIDump/APIDesc.lua | 3 ++- src/Server.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index ce3303087..90d95bba2 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2172,10 +2172,11 @@ end { GetDescription = { Return = "string", Notes = "Returns the server description set in the settings.ini." }, GetMaxPlayers = { Return = "number", Notes = "Returns the max amount of players who can join the server." }, - SetMaxPlayers = { Params = "number", Notes = "Sets the max amount of players who can join." }, GetNumPlayers = { Return = "number", Notes = "Returns the amount of players online." }, GetServerID = { Return = "string", Notes = "Returns the ID of the server?" }, IsHardcore = { Params = "", Return = "bool", Notes = "Returns true if the server is hardcore (players get banned on death)." }, + SetMaxPlayers = { Params = "number", Notes = "Sets the max amount of players who can join." }, + ShouldAuthenticate = { Params = "", Return = "bool", Notes = "Returns true iff the server is set to authenticate players (\"online mode\")." }, }, }, -- cServer diff --git a/src/Server.h b/src/Server.h index c1640b388..f20e6932f 100644 --- a/src/Server.h +++ b/src/Server.h @@ -120,7 +120,7 @@ public: // tolua_export const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; } /** Returns true if authentication has been turned on in server settings. */ - bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; } + bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; } // tolua_export /** Returns true if offline UUIDs should be used to load data for players whose normal UUIDs cannot be found. Loaded from the settings.ini [PlayerData].LoadOfflinePlayerData setting. */ From b7ec75add6c0904b3950ce13ebe16888fd237c05 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 22:27:58 +0200 Subject: [PATCH 040/102] Updated the Core. --- MCServer/Plugins/Core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 1b16c23c2..6627e570a 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 1b16c23c216d359e9fe0334c63deeecc347e69bd +Subproject commit 6627e570a5265ae270aae978a1cad80dfb8a2b18 From 936604ca95d8e639a6783f9931093b689ce103d9 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:19:30 +0200 Subject: [PATCH 041/102] cMojangAPI: Fixed MakeUUID___() bindings. ToLua would generate a shadow return value for the input strings. --- src/Bindings/ManualBindings.cpp | 58 +++++++++++++++++++++++++++++++++ src/Protocol/MojangAPI.h | 4 --- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index a60408910..834f6e073 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2414,6 +2414,62 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) +static int tolua_cMojangAPI_MakeUUIDDashed(lua_State * L) +{ + // Function signature: cMojangAPI:MakeUUIDDashed(UUID) -> string + + // Check params: + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cMojangAPI") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString UUID; + S.GetStackValue(2, UUID); + + // Push the result: + S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDDashed(UUID)); + return 1; +} + + + + + +static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L) +{ + // Function signature: cMojangAPI:MakeUUIDShort(UUID) -> string + + // Check params: + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cMojangAPI") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString UUID; + S.GetStackValue(2, UUID); + + // Push the result: + S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDShort(UUID)); + return 1; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -3355,6 +3411,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "GetPlayerNameFromUUID", tolua_cMojangAPI_GetPlayerNameFromUUID); tolua_function(tolua_S, "GetUUIDFromPlayerName", tolua_cMojangAPI_GetUUIDFromPlayerName); tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cMojangAPI_GetUUIDsFromPlayerNames); + tolua_function(tolua_S, "MakeUUIDDashed", tolua_cMojangAPI_MakeUUIDDashed); + tolua_function(tolua_S, "MakeUUIDShort", tolua_cMojangAPI_MakeUUIDShort); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 6ed37625e..e96c0d589 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -38,8 +38,6 @@ public: Returns true if all was successful, false on failure. */ static bool SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response); - // tolua_begin - /** Normalizes the given UUID to its short form (32 bytes, no dashes, lowercase). Logs a warning and returns empty string if not a UUID. Note: only checks the string's length, not the actual content. */ @@ -50,8 +48,6 @@ public: Note: only checks the string's length, not the actual content. */ static AString MakeUUIDDashed(const AString & a_UUID); - // tolua_end - /** Converts a player name into a UUID. The UUID will be empty on error. If a_UseOnlyCached is true, the function only consults the cached values. From 8acc8831879582e24c53c18d0442db0b1df6c6b6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:29:54 +0200 Subject: [PATCH 042/102] Removed cGroup and cGroupManager. --- src/Bindings/AllToLua.pkg | 1 - src/CMakeLists.txt | 4 - src/Entities/Player.cpp | 2 - src/Group.cpp | 41 ------- src/Group.h | 44 -------- src/GroupManager.cpp | 227 -------------------------------------- src/GroupManager.h | 36 ------ src/Root.cpp | 16 --- src/Root.h | 6 - src/Server.cpp | 28 ++--- 10 files changed, 9 insertions(+), 396 deletions(-) delete mode 100644 src/Group.cpp delete mode 100644 src/Group.h delete mode 100644 src/GroupManager.cpp delete mode 100644 src/GroupManager.h diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 88faa9dfc..37e6aecd2 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -67,7 +67,6 @@ $cfile "../Root.h" $cfile "../Cuboid.h" $cfile "../BoundingBox.h" $cfile "../Tracer.h" -$cfile "../Group.h" $cfile "../BlockArea.h" $cfile "../Generating/ChunkDesc.h" $cfile "../CraftingRecipes.h" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 738b53537..79baf317d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,8 +33,6 @@ SET (SRCS FastRandom.cpp FurnaceRecipe.cpp Globals.cpp - Group.cpp - GroupManager.cpp Inventory.cpp Item.cpp ItemGrid.cpp @@ -98,8 +96,6 @@ SET (HDRS ForEachChunkProvider.h FurnaceRecipe.h Globals.h - Group.h - GroupManager.h Inventory.h Item.h ItemGrid.h diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 423ca3317..b6d6fc7b0 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -10,8 +10,6 @@ #include "../Bindings/PluginManager.h" #include "../BlockEntities/BlockEntity.h" #include "../BlockEntities/EnderChestEntity.h" -#include "../GroupManager.h" -#include "../Group.h" #include "../Root.h" #include "../OSSupport/Timer.h" #include "../Chunk.h" diff --git a/src/Group.cpp b/src/Group.cpp deleted file mode 100644 index def585618..000000000 --- a/src/Group.cpp +++ /dev/null @@ -1,41 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Group.h" - - - - - -void cGroup::AddCommand( const AString & a_Command) -{ - m_Commands[ a_Command ] = true; -} - - - - - -void cGroup::AddPermission( const AString & a_Permission) -{ - m_Permissions[ a_Permission ] = true; -} - - - - - -void cGroup::InheritFrom( cGroup* a_Group) -{ - m_Inherits.remove( a_Group); - m_Inherits.push_back( a_Group); -} - - - - - -void cGroup::ClearPermission() -{ - m_Permissions.clear(); -} diff --git a/src/Group.h b/src/Group.h deleted file mode 100644 index 5816f8a06..000000000 --- a/src/Group.h +++ /dev/null @@ -1,44 +0,0 @@ - -#pragma once - - - - - -// tolua_begin -class cGroup -{ -public: - // tolua_end - cGroup() {} - ~cGroup() {} - - // tolua_begin - void SetName( const AString & a_Name) { m_Name = a_Name; } - const AString & GetName() const { return m_Name; } - void SetColor( const AString & a_Color) { m_Color = a_Color; } - void AddCommand( const AString & a_Command); - void AddPermission( const AString & a_Permission); - void InheritFrom( cGroup* a_Group); - // tolua_end - - typedef std::map< AString, bool > PermissionMap; - const PermissionMap & GetPermissions() const { return m_Permissions; } - - void ClearPermission(void); - - typedef std::map< AString, bool > CommandMap; - const CommandMap & GetCommands() const { return m_Commands; } - - const AString & GetColor() const { return m_Color; } // tolua_export - - typedef std::list< cGroup* > GroupList; - const GroupList & GetInherits() const { return m_Inherits; } -private: - AString m_Name; - AString m_Color; - - PermissionMap m_Permissions; - CommandMap m_Commands; - GroupList m_Inherits; -}; // tolua_export diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp deleted file mode 100644 index 4c3dfc6f0..000000000 --- a/src/GroupManager.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "GroupManager.h" -#include "Group.h" -#include "inifile/iniFile.h" -#include "ChatColor.h" -#include "Root.h" - - - - - -typedef std::map< AString, cGroup* > GroupMap; - - - - - -struct cGroupManager::sGroupManagerState -{ - GroupMap Groups; -}; - - - - - -cGroupManager::~cGroupManager() -{ - for (GroupMap::iterator itr = m_pState->Groups.begin(); itr != m_pState->Groups.end(); ++itr) - { - delete itr->second; - itr->second = NULL; - } - m_pState->Groups.clear(); - - delete m_pState; - m_pState = NULL; -} - - - - - -cGroupManager::cGroupManager() - : m_pState( new sGroupManagerState) -{ - LOGD("-- Loading Groups --"); - - if (!LoadGroups()) - { - LOGWARNING("ERROR: Groups could not load!"); - } - if (!CheckUsers()) - { - LOGWARNING("ERROR: User file could not be found!"); - } - - LOGD("-- Groups Successfully Loaded --"); -} - - - - - -void cGroupManager::GenerateDefaultUsersIni(cIniFile & a_IniFile) -{ - LOGWARN("Regenerating users.ini, all users will be reset"); - a_IniFile.AddHeaderComment(" This file stores the players' groups."); - a_IniFile.AddHeaderComment(" The format is:"); - a_IniFile.AddHeaderComment(" [PlayerName]"); - a_IniFile.AddHeaderComment(" Groups = GroupName1, GroupName2, ..."); - - a_IniFile.WriteFile("users.ini"); -} - - - - - -bool cGroupManager::CheckUsers() -{ - cIniFile IniFile; - if (!IniFile.ReadFile("users.ini")) - { - GenerateDefaultUsersIni(IniFile); - return true; - } - - int NumKeys = IniFile.GetNumKeys(); - for (int i = 0; i < NumKeys; i++) - { - AString Player = IniFile.GetKeyName(i); - AString Groups = IniFile.GetValue(Player, "Groups", ""); - if (Groups.empty()) - { - continue; - } - AStringVector Split = StringSplitAndTrim(Groups, ","); - for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) - { - if (!ExistsGroup(*itr)) - { - LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str()); - } - } // for itr - Split[] - } // for i - ini file keys - // Always return true for now, just but we can handle writefile fails later. - return true; -} - - - - - -bool cGroupManager::LoadGroups() -{ - cIniFile IniFile; - if (!IniFile.ReadFile("groups.ini")) - { - LOGWARNING("Regenerating groups.ini, all groups will be reset"); - IniFile.AddHeaderComment(" This is the MCServer permissions manager groups file"); - IniFile.AddHeaderComment(" It stores all defined groups such as Administrators, Players, or Moderators"); - - IniFile.SetValue("Owner", "Permissions", "*", true); - IniFile.SetValue("Owner", "Color", "2", true); - - IniFile.SetValue("Moderator", "Permissions", "core.time, core.item, core.tpa, core.tpaccept, core.ban, core.unban, core.save-all, core.toggledownfall"); - IniFile.SetValue("Moderator", "Color", "2", true); - IniFile.SetValue("Moderator", "Inherits", "Player", true); - - IniFile.SetValue("Player", "Permissions", "core.portal", true); - IniFile.SetValue("Player", "Color", "f", true); - IniFile.SetValue("Player", "Inherits", "Default", true); - - IniFile.SetValue("Default", "Permissions", "core.help, core.plugins, core.spawn, core.worlds, core.back, core.motd, core.build, core.locate, core.viewdistance", true); - IniFile.SetValue("Default", "Color", "f", true); - - IniFile.WriteFile("groups.ini"); - } - - int NumKeys = IniFile.GetNumKeys(); - for (int i = 0; i < NumKeys; i++) - { - AString KeyName = IniFile.GetKeyName(i); - cGroup * Group = GetGroup(KeyName.c_str()); - - Group->ClearPermission(); // Needed in case the groups are reloaded. - - LOGD("Loading group %s", KeyName.c_str()); - - Group->SetName(KeyName); - AString Color = IniFile.GetValue(KeyName, "Color", "-"); - if ((Color != "-") && (Color.length() >= 1)) - { - Group->SetColor(AString(cChatColor::Delimiter) + Color[0]); - } - else - { - Group->SetColor(cChatColor::White); - } - - AString Commands = IniFile.GetValue(KeyName, "Commands", ""); - if (!Commands.empty()) - { - AStringVector Split = StringSplitAndTrim(Commands, ","); - for (size_t i = 0; i < Split.size(); i++) - { - Group->AddCommand(Split[i]); - } - } - - AString Permissions = IniFile.GetValue(KeyName, "Permissions", ""); - if (!Permissions.empty()) - { - AStringVector Split = StringSplitAndTrim(Permissions, ","); - for (size_t i = 0; i < Split.size(); i++) - { - Group->AddPermission(Split[i]); - } - } - - AString Groups = IniFile.GetValue(KeyName, "Inherits", ""); - if (!Groups.empty()) - { - AStringVector Split = StringSplitAndTrim(Groups, ","); - for (size_t i = 0; i < Split.size(); i++) - { - Group->InheritFrom(GetGroup(Split[i].c_str())); - } - } - } - // Always return true, we can handle writefile fails later. - return true; -} - - - - - -bool cGroupManager::ExistsGroup( const AString & a_Name) -{ - GroupMap::iterator itr = m_pState->Groups.find( a_Name); - return ( itr != m_pState->Groups.end()); -} - - - - - -cGroup* cGroupManager::GetGroup( const AString & a_Name) -{ - GroupMap::iterator itr = m_pState->Groups.find( a_Name); - if (itr != m_pState->Groups.end()) - { - return itr->second; - } - - cGroup* Group = new cGroup(); - m_pState->Groups[a_Name] = Group; - - return Group; -} - - - - diff --git a/src/GroupManager.h b/src/GroupManager.h deleted file mode 100644 index d42b55c4a..000000000 --- a/src/GroupManager.h +++ /dev/null @@ -1,36 +0,0 @@ - -#pragma once - - - - - -class cGroup; - - - - - -class cGroupManager -{ -public: - bool ExistsGroup(const AString & a_Name); - cGroup * GetGroup(const AString & a_Name); - bool LoadGroups(); - bool CheckUsers(); - - /** Writes the default header to the specified ini file, and saves it as "users.ini". */ - static void GenerateDefaultUsersIni(cIniFile & a_IniFile); - -private: - friend class cRoot; - cGroupManager(); - ~cGroupManager(); - - struct sGroupManagerState; - sGroupManagerState * m_pState; -} ; - - - - diff --git a/src/Root.cpp b/src/Root.cpp index 333d92de5..18221781d 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -6,7 +6,6 @@ #include "World.h" #include "WebAdmin.h" #include "FurnaceRecipe.h" -#include "GroupManager.h" #include "CraftingRecipes.h" #include "Bindings/PluginManager.h" #include "MonsterConfig.h" @@ -46,7 +45,6 @@ cRoot::cRoot(void) : m_InputThread(NULL), m_Server(NULL), m_MonsterConfig(NULL), - m_GroupManager(NULL), m_CraftingRecipes(NULL), m_FurnaceRecipe(NULL), m_WebAdmin(NULL), @@ -157,7 +155,6 @@ void cRoot::Start(void) LOGD("Loading settings..."); m_RankManager.Initialize(m_MojangAPI); - m_GroupManager = new cGroupManager(); m_CraftingRecipes = new cCraftingRecipes; m_FurnaceRecipe = new cFurnaceRecipe(); @@ -236,8 +233,6 @@ void cRoot::Start(void) LOGD("Unloading recipes..."); delete m_FurnaceRecipe; m_FurnaceRecipe = NULL; delete m_CraftingRecipes; m_CraftingRecipes = NULL; - LOGD("Forgetting groups..."); - delete m_GroupManager; m_GroupManager = NULL; LOGD("Unloading worlds..."); UnloadWorlds(); @@ -546,17 +541,6 @@ void cRoot::SaveAllChunks(void) -void cRoot::ReloadGroups(void) -{ - LOG("Reload groups ..."); - m_GroupManager->LoadGroups(); - m_GroupManager->CheckUsers(); -} - - - - - void cRoot::BroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix) { for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr) diff --git a/src/Root.h b/src/Root.h index 68469c72f..2e870a1ee 100644 --- a/src/Root.h +++ b/src/Root.h @@ -14,7 +14,6 @@ // fwd: class cThread; class cMonsterConfig; -class cGroupManager; class cCraftingRecipes; class cFurnaceRecipe; class cWebAdmin; @@ -79,7 +78,6 @@ public: cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; } - cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature @@ -124,9 +122,6 @@ public: /// Saves all chunks in all worlds void SaveAllChunks(void); // tolua_export - /// Reloads all the groups - void ReloadGroups(void); // tolua_export - /// Calls the callback for each player in all worlds bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << @@ -189,7 +184,6 @@ private: cServer * m_Server; cMonsterConfig * m_MonsterConfig; - cGroupManager * m_GroupManager; cCraftingRecipes * m_CraftingRecipes; cFurnaceRecipe * m_FurnaceRecipe; cWebAdmin * m_WebAdmin; diff --git a/src/Server.cpp b/src/Server.cpp index 42ad133f1..012a51883 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -11,7 +11,6 @@ #include "World.h" #include "ChunkDef.h" #include "Bindings/PluginManager.h" -#include "GroupManager.h" #include "ChatColor.h" #include "Entities/Player.h" #include "Inventory.h" @@ -469,25 +468,17 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac PrintHelp(split, a_Output); return; } - if (split[0] == "reload") - { - cPluginManager::Get()->ReloadPlugins(); - cRoot::Get()->ReloadGroups(); - return; - } - if (split[0] == "reloadplugins") + else if (split[0] == "reload") { cPluginManager::Get()->ReloadPlugins(); return; } - if (split[0] == "reloadgroups") + else if (split[0] == "reloadplugins") { - cRoot::Get()->ReloadGroups(); - a_Output.Out("Groups reloaded!"); - a_Output.Finished(); + cPluginManager::Get()->ReloadPlugins(); return; } - if (split[0] == "load") + else if (split[0] == "load") { if (split.size() > 1) { @@ -502,8 +493,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac return; } } - - if (split[0] == "unload") + else if (split[0] == "unload") { if (split.size() > 1) { @@ -519,21 +509,21 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac } // There is currently no way a plugin can do these (and probably won't ever be): - if (split[0].compare("chunkstats") == 0) + else if (split[0].compare("chunkstats") == 0) { cRoot::Get()->LogChunkStats(a_Output); a_Output.Finished(); return; } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - if (split[0].compare("dumpmem") == 0) + else if (split[0].compare("dumpmem") == 0) { LeakFinderXmlOutput Output("memdump.xml"); DumpUsedMemory(&Output); return; } - if (split[0].compare("killmem") == 0) + else if (split[0].compare("killmem") == 0) { for (;;) { @@ -542,7 +532,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac } #endif - if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output)) + else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output)) { a_Output.Finished(); return; From 011ff52407fc3eee80319f7f3bd22558824763a1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:46:43 +0200 Subject: [PATCH 043/102] APIDump: Removed the cGroup and cGroupManager classes. --- MCServer/Plugins/APIDump/APIDesc.lua | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 90d95bba2..c474b5eb0 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -942,24 +942,6 @@ cFile:Delete("/usr/bin/virus.exe"); Inherits = "cEntity", }, - cGroup = - { - Desc = [[ - This class represents a group {{cPlayer|players}} can be in. Groups define the permissions players - have, and optionally the color of their name in the chat. - ]], - Functions = - { - SetName = { Return = "" }, - GetName = { Return = "string" }, - SetColor = { Return = "" }, - GetColor = { Return = "string" }, - AddCommand = { Return = "" }, - AddPermission = { Return = "" }, - InheritFrom = { Return = "" }, - }, - }, -- cGroup - cIniFile = { Desc = [[ @@ -1760,7 +1742,6 @@ a_Player:OpenWindow(Window); Functions = { AddFoodExhaustion = { Params = "Exhaustion", Return = "", Notes = "Adds the specified number to the food exhaustion. Only positive numbers expected." }, - AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." }, CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "(STATIC) Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." }, CanFly = { Return = "bool", Notes = "Returns if the player is able to fly." }, CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." }, @@ -1770,7 +1751,7 @@ a_Player:OpenWindow(Window); FoodPoison = { Params = "NumTicks", Return = "", Notes = "Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two" }, ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." }, GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." }, - GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." }, + GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player's messages (based on their rank). Prefix player messages with this code." }, GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" }, GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." }, GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, @@ -1784,7 +1765,6 @@ a_Player:OpenWindow(Window); GetFoodSaturationLevel = { Params = "", Return = "number", Notes = "Returns the food saturation (overcharge of the food level, is depleted before food level)" }, GetFoodTickTimer = { Params = "", Return = "", Notes = "Returns the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." }, GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.
NOTE: Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."}, - GetGroups = { Return = "array-table of {{cGroup}}", Notes = "Returns all the groups that this player is member of, as a table. The groups are stored in the array part of the table, beginning with index 1."}, GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."}, GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"}, GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." }, @@ -1807,15 +1787,13 @@ a_Player:OpenWindow(Window); IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmAdventure gamemode, or has their gamemode unset and the world is a gmAdventure world." }, IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmCreative gamemode, or has their gamemode unset and the world is a gmCreative world." }, IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmSurvival gamemode, or has their gamemode unset and the world is a gmSurvival world." }, - IsInGroup = { Params = "GroupNameString", Return = "bool", Notes = "Returns true if the player is a member of the specified group." }, IsOnGround = { Params = "", Return = "bool", Notes = "Returns true if the player is on ground (not falling, not jumping, not flying)" }, IsSatiated = { Params = "", Return = "bool", Notes = "Returns true if the player is satiated (cannot eat)." }, IsVisible = { Params = "", Return = "bool", Notes = "Returns true if the player is visible to other players" }, - LoadPermissionsFromDisk = { Params = "", Return = "", Notes = "Reloads the player's permissions from the disk. This loses any temporary changes made to the player's groups." }, + LoadRank = { Params = "", Return = "", Notes = "Reloads the player's rank, message visuals and permissions from the {{cRankManager}}, based on the player's current rank." }, MoveTo = { Params = "{{Vector3d|NewPosition}}", Return = "Tries to move the player into the specified position." }, MoveToWorld = { Params = "WorldName", Return = "bool", Return = "Moves the player to the specified world. Returns true if successful." }, OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." }, - RemoveFromGroup = { Params = "GroupName", Return = "", Notes = "Temporarily removes the player from the specified group. This change is lost when the player disconnects." }, Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." }, SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." }, SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." }, @@ -2088,7 +2066,6 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." }, GetFurnaceFuelBurnTime = { Params = "{{cItem|Fuel}}", Return = "number", Notes = "(STATIC) Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel." }, GetFurnaceRecipe = { Params = "{{cItem|InItem}}", Return = "{{cItem|OutItem}}, NumTicks, {{cItem|InItem}}", Notes = "(STATIC) Returns the furnace recipe for smelting the specified input. If a recipe is found, returns the smelted result, the number of ticks required for the smelting operation, and the input consumed (note that MCServer supports smelting M items into N items and different smelting rates). If no recipe is found, returns no value." }, - GetGroupManager = { Params = "", Return = "{{cGroupManager|cGroupManager}}", Notes = "Returns the cGroupManager object." }, GetPhysicalRAMUsage = { Params = "", Return = "number", Notes = "Returns the amount of physical RAM that the entire MCServer process is using, in KiB. Negative if the OS doesn't support this query." }, GetPluginManager = { Params = "", Return = "{{cPluginManager|cPluginManager}}", Notes = "Returns the cPluginManager object." }, GetPrimaryServerVersion = { Params = "", Return = "number", Notes = "Returns the servers primary server version." }, From b8d3ddb40992699e8d01f74b829b44047fdef048 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:49:32 +0200 Subject: [PATCH 044/102] Removed Group.h from Bindings' dependencies. --- src/Bindings/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index b87192b47..7a1769e9a 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -97,7 +97,6 @@ set(BINDING_DEPENDENCIES ../Entities/HangingEntity.h ../Entities/ItemFrame.h ../Generating/ChunkDesc.h - ../Group.h ../Inventory.h ../Item.h ../ItemGrid.h From 263ea5464b6761f7442d642006f9b9728b153ec1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:53:22 +0200 Subject: [PATCH 045/102] Removed last remnant of cGroup. --- src/Entities/Player.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index bfafcb7fb..9821cc6d9 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -13,7 +13,6 @@ -class cGroup; class cWindow; class cClientHandle; class cTeam; From 326dd7e4c6baa6070d35a2a46ca20404c623c8e1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 16:55:39 +0200 Subject: [PATCH 046/102] RankMgr: Added cRankManager::RemovePlayerRank(). --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + src/Bindings/ManualBindings_RankManager.cpp | 30 +++++++++++++++++++++ src/RankManager.cpp | 23 ++++++++++++++++ src/RankManager.h | 6 +++++ 4 files changed, 60 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index c474b5eb0..6138f945a 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2030,6 +2030,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); RemoveGroup = { Params = "GroupName", Return = "", Notes = "Removes the specified group completely. The group will be removed from all the ranks using it and then erased from the manager. Logs an info message and does nothing if the group doesn't exist." }, RemoveGroupFromRank = { Params = "GroupName, RankName", Return = "", Notes = "Removes the specified group from the specified rank. The group will still exist, even if it isn't assigned to any rank. Logs an info message and does nothing if the group or rank doesn't exist." }, RemovePermissionFromGroup = { Params = "Permission, GroupName", Return = "", Notes = "Removes the specified permission from the specified group. Logs an info message and does nothing if the group doesn't exist." }, + RemovePlayerRank = { Params = "PlayerUUID", Return = "", Notes = "Removes the player's rank; the player's left without a rank. Note that this doesn't change the {{cPlayer}} instances for the already connected players, you need to update all the instances manually. No action if the player has no rank assigned to them already." }, RemoveRank = { Params = "RankName, [ReplacementRankName]", Return = "", Notes = "Removes the specified rank. If ReplacementRankName is given, the players that have RankName will get their rank set to ReplacementRankName. If it isn't given, or is an invalid rank, the players will be removed from the manager, their ranks will be unset completely. Logs an info message and does nothing if the rank is not found." }, RenameGroup = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified group. Logs an info message and does nothing if the group is not found." }, RenameRank = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified rank. Logs an info message and does nothing if the rank is not found." }, diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index bc31ea687..5351c028d 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -717,6 +717,35 @@ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) +/** Binds cRankManager::RemovePlayerRank */ +static int tolua_cRankManager_RemovePlayerRank(lua_State * L) +{ + // function signature: + // cRankManager:RemovePlayerRank(PlayerUUID) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Remove the player's rank: + cRoot::Get()->GetRankManager().RemovePlayerRank(PlayerUUID); + return 0; +} + + + + + /** Binds cRankManager::RemoveRank */ static int tolua_cRankManager_RemoveRank(lua_State * L) { @@ -900,6 +929,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "RemoveGroup", tolua_cRankManager_RemoveGroup); tolua_function(tolua_S, "RemoveGroupFromRank", tolua_cRankManager_RemoveGroupFromRank); tolua_function(tolua_S, "RemovePermissionFromGroup", tolua_cRankManager_RemovePermissionFromGroup); + tolua_function(tolua_S, "RemovePlayerRank", tolua_cRankManager_RemovePlayerRank); tolua_function(tolua_S, "RemoveRank", tolua_cRankManager_RemoveRank); tolua_function(tolua_S, "RenameGroup", tolua_cRankManager_RenameGroup); tolua_function(tolua_S, "RenameRank", tolua_cRankManager_RenameRank); diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 96c4baa56..65e5d264c 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -1424,6 +1424,29 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a +void cRankManager::RemovePlayerRank(const AString & a_PlayerUUID) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE PlayerUUID = ?"); + stmt.bind(1, a_PlayerUUID); + stmt.exec(); + } + catch(const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to remove rank from player UUID %s: %s", + __FUNCTION__, a_PlayerUUID.c_str(), ex.what() + ); + } +} + + + + + void cRankManager::SetRankVisuals( const AString & a_RankName, const AString & a_MsgPrefix, diff --git a/src/RankManager.h b/src/RankManager.h index 3ccbd2fd4..532b4cd83 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -155,6 +155,12 @@ public: cPlayer instances manually. The PlayerName is provided for reference, so that GetRankPlayerNames() can work. */ void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName); + + /** Removes the player's rank assignment. The player is left without a rank. + Note that this doesn't change the cPlayer instances for the already connected players, you need to update + all the instances manually. + No action if the player has no rank assigned to them already. */ + void RemovePlayerRank(const AString & a_PlayerUUID); /** Sets the message visuals of an existing rank. No action if the rank name is not found. */ void SetRankVisuals( From 0c04bf962ed025789c1979c6d4fb122735b1a46b Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 20:47:52 +0200 Subject: [PATCH 047/102] cMojangAPI updates cRankManager's playernames. --- src/Protocol/MojangAPI.cpp | 19 +++++++++++++++++++ src/Protocol/MojangAPI.h | 22 ++++++++++++++++++++- src/RankManager.cpp | 39 +++++++++++++++++++++++++++++++++++++- src/RankManager.h | 9 +++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 823ff5469..3786fecc9 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -10,6 +10,7 @@ #include "inifile/iniFile.h" #include "json/json.h" #include "PolarSSL++/BlockingSslClientSocket.h" +#include "../RankManager.h" @@ -300,6 +301,7 @@ void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const cCSLock Lock(m_CSUUIDToName); m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now); } + NotifyNameUUID(a_PlayerName, a_UUID); } @@ -322,6 +324,7 @@ void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[UUID] = sProfile(a_PlayerName, UUID, a_Properties, Now); } + NotifyNameUUID(a_PlayerName, a_UUID); } @@ -669,6 +672,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); + NotifyNameUUID(JsonName, JsonUUID); } // for idx - root[] } // cCSLock (m_CSNameToUUID) @@ -792,6 +796,21 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); } + NotifyNameUUID(PlayerName, a_UUID); +} + + + + + +void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID) +{ + // Notify the rank manager: + cCSLock Lock(m_CSRankMgr); + if (m_RankMgr != NULL) + { + m_RankMgr->NotifyNameUUID(a_PlayerName, a_UUID); + } } diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index e96c0d589..252d32543 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -11,6 +11,13 @@ #include + + + + +// fwd: ../RankManager.h" +class cRankManager; + namespace Json { class Value; @@ -81,7 +88,10 @@ public: /** Called by the Authenticator to add a profile that it has received from authenticating a user. Adds the profile to the respective mapping caches and updtes their datetime stamp to now. */ void AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties); - + + /** Sets the m_RankMgr that is used for name-uuid notifications. Accepts NULL to remove the binding. */ + void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; } + protected: /** Holds data for a single player profile. */ struct sProfile @@ -161,6 +171,12 @@ protected: /** Protects m_UUIDToProfile against simultaneous multi-threaded access. */ cCriticalSection m_CSUUIDToProfile; + + /** The rank manager that is notified of the name-uuid pairings. May be NULL. Protected by m_CSRankMgr. */ + cRankManager * m_RankMgr; + + /** Protects m_RankMgr agains simultaneous multi-threaded access. */ + cCriticalSection m_CSRankMgr; /** Loads the caches from a disk storage. */ @@ -178,6 +194,10 @@ protected: UUIDs that are not valid will not be added into the cache. ASSUMEs that a_UUID is a lowercased short UUID. */ void CacheUUIDToProfile(const AString & a_UUID); + + /** Called for each name-uuid pairing that is discovered. + If assigned, notifies the m_RankManager of the event. */ + void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID); } ; // tolua_export diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 65e5d264c..349582950 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -365,7 +365,8 @@ protected: cRankManager::cRankManager(void) : m_DB("Ranks.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), - m_IsInitialized(false) + m_IsInitialized(false), + m_MojangAPI(NULL) { } @@ -373,6 +374,18 @@ cRankManager::cRankManager(void) : +cRankManager::~cRankManager() +{ + if (m_MojangAPI != NULL) + { + m_MojangAPI->SetRankManager(NULL); + } +} + + + + + void cRankManager::Initialize(cMojangAPI & a_MojangAPI) { ASSERT(!m_IsInitialized); // Calling Initialize for the second time? @@ -386,6 +399,8 @@ void cRankManager::Initialize(cMojangAPI & a_MojangAPI) m_IsInitialized = true; + a_MojangAPI.SetRankManager(this); + // Check if tables empty, migrate from ini files then if (AreDBTablesEmpty()) { @@ -1655,6 +1670,28 @@ bool cRankManager::IsPermissionInGroup(const AString & a_Permission, const AStri +void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?"); + stmt.bind(1, a_PlayerName); + stmt.bind(2, a_UUID); + stmt.exec(); + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what()); + } +} + + + + + bool cRankManager::AreDBTablesEmpty(void) { return ( diff --git a/src/RankManager.h b/src/RankManager.h index 532b4cd83..24030ef22 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -49,6 +49,8 @@ public: /** Creates the rank manager. Needs to be initialized before other use. */ cRankManager(void); + + ~cRankManager(); /** Initializes the rank manager. Performs migration and default-setting if no data is found in the DB. The a_MojangAPI param is used when migrating from old ini files, to look up player UUIDs. */ @@ -194,6 +196,9 @@ public: /** Returns true iff the specified group contains the specified permission. */ bool IsPermissionInGroup(const AString & a_Permission, const AString & a_GroupName); + /** Called by cMojangAPI whenever the playername-uuid pairing is discovered. Updates the DB. */ + void NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID); + protected: /** The database storage for all the data. Protected by m_CS. */ @@ -204,6 +209,10 @@ protected: /** Set to true once the manager is initialized. */ bool m_IsInitialized; + + /** The MojangAPI instance that is used for translating playernames to UUIDs. + Set in Initialize(), may be NULL. */ + cMojangAPI * m_MojangAPI; /** Returns true if all the DB tables are empty, indicating a fresh new install. */ From 1e5d770d7f55c8d6ce7c0afa3bc75d416e6ac935 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:37:52 +0200 Subject: [PATCH 048/102] Fixed a compile-time warning in MSVC. --- src/Bindings/PluginLua.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index d0b4fa617..ad8528114 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -842,7 +842,7 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d a_OldPosition cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), &a_Player, &a_OldPosition, &a_NewPosition, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, a_OldPosition, a_NewPosition, cLuaState::Return, res); if (res) { return true; From c22261252f98e3bb5f0f319c610ad6990b6e199f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:38:21 +0200 Subject: [PATCH 049/102] Sorted the generated param count. --- src/Bindings/gen_LuaState_Call.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index c1d1af771..13ef8b882 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -54,9 +54,9 @@ local Combinations = {9, 2}, -- Special combinations: + {5, 5}, {7, 3}, {8, 3}, - {5, 5}, {9, 5}, } From d471ee8a9d93d1c793db316b00dcc8eddcdc2c2a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:38:57 +0200 Subject: [PATCH 050/102] Fixed 1.7.2 login packet reading. Fixes #1317. --- src/Protocol/Protocol17x.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index a8df948cd..1091b877f 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1824,7 +1824,11 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) { AString Username; - a_ByteBuffer.ReadVarUTF8String(Username); + if (!a_ByteBuffer.ReadVarUTF8String(Username)) + { + m_Client->Kick("Bad username"); + return; + } if (!m_Client->HandleHandshake(Username)) { From 81d238e0805eb8bd5ae3e844129bd11d62e1e8fd Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:53:25 +0200 Subject: [PATCH 051/102] Added cWorld initializers. --- src/World.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/World.cpp b/src/World.cpp index 2027e215a..d7fa7e0d1 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -251,8 +251,38 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_TimeOfDay(0), m_LastTimeUpdate(0), m_SkyDarkness(0), + m_GameMode(gmNotSet), + m_bEnabledPVP(false), + m_IsDeepSnowEnabled(false), + m_ShouldLavaSpawnFire(true), + m_VillagersShouldHarvestCrops(true), + m_SimulatorManager(NULL), + m_SandSimulator(NULL), + m_WaterSimulator(NULL), + m_LavaSimulator(NULL), + m_FireSimulator(NULL), + m_RedstoneSimulator(NULL), + m_MaxPlayers(10), + m_ChunkMap(NULL), + m_bAnimals(true), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) + m_MaxCactusHeight(3), + m_MaxSugarcaneHeight(4), + m_IsCactusBonemealable(false), + m_IsCarrotsBonemealable(true), + m_IsCropsBonemealable(true), + m_IsGrassBonemealable(true), + m_IsMelonStemBonemealable(true), + m_IsMelonBonemealable(true), + m_IsPotatoesBonemealable(true), + m_IsPumpkinStemBonemealable(true), + m_IsPumpkinBonemealable(true), + m_IsSaplingBonemealable(true), + m_IsSugarcaneBonemealable(false), + m_bCommandBlocksEnabled(true), + m_bUseChatPrefixes(false), + m_TNTShrapnelLevel(slNone), m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), From 4358421cd46dd8d8275aba964e9a1532c34439d8 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:58:08 +0200 Subject: [PATCH 052/102] cSetChunkData: Added missing initializers. --- src/SetChunkData.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index 6e0c2733e..af6ad1251 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -13,6 +13,9 @@ cSetChunkData::cSetChunkData(int a_ChunkX, int a_ChunkZ, bool a_ShouldMarkDirty) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), + m_IsLightValid(false), + m_IsHeightMapValid(false), + m_AreBiomesValid(false), m_ShouldMarkDirty(a_ShouldMarkDirty) { } From 64fec204c4c5062461a7188b58026d062519b417 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 22:39:53 +0200 Subject: [PATCH 053/102] Added initializers for class members. As reported by Coverity, these weren't initialized. --- src/BlockArea.cpp | 4 +++- src/ChunkDef.h | 2 +- src/ClientHandle.cpp | 10 ++++++++++ src/DeadlockDetect.cpp | 4 +++- src/Generating/Caves.cpp | 3 +++ src/Generating/ChunkGenerator.cpp | 1 + src/Generating/HeiGen.cpp | 8 +++++++- src/HTTPServer/HTTPConnection.cpp | 3 ++- src/HTTPServer/HTTPFormParser.cpp | 8 ++++++-- src/LightingThread.cpp | 6 +++++- src/Noise.cpp | 5 +++++ src/PolarSSL++/SslContext.cpp | 1 + src/Server.cpp | 4 +++- src/WorldStorage/FastNBT.h | 4 ++++ 14 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index a0dcb5ec8..90f7ca6c9 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -1764,7 +1764,9 @@ NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBL cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) : m_Area(a_Area), - m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z) + m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z), + m_CurrentChunkX(0), + m_CurrentChunkZ(0) { } diff --git a/src/ChunkDef.h b/src/ChunkDef.h index dbb782d26..51075ab4a 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -419,7 +419,7 @@ public: X Data; cCoordWithData(int a_X, int a_Y, int a_Z) : - x(a_X), y(a_Y), z(a_Z) + x(a_X), y(a_Y), z(a_Z), Data() { } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index e2b438831..ee4fdfa7d 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -75,11 +75,21 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : m_TimeSinceLastPacket(0), m_Ping(1000), m_PingID(1), + m_PingStartTime(0), + m_LastPingTime(1000), m_BlockDigAnimStage(-1), + m_BlockDigAnimSpeed(0), + m_BlockDigAnimX(0), + m_BlockDigAnimY(256), // Invalid Y, so that the coords don't get picked up + m_BlockDigAnimZ(0), m_HasStartedDigging(false), + m_LastDigBlockX(0), + m_LastDigBlockY(256), // Invalid Y, so that the coords don't get picked up + m_LastDigBlockZ(0), m_State(csConnected), m_ShouldCheckDownloaded(false), m_NumExplosionsThisTick(0), + m_NumBlockChangeInteractionsThisTick(0), m_UniqueID(0), m_HasSentPlayerChunk(false), m_Locale("en_GB") diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index f73a45555..7f703416c 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -21,7 +21,8 @@ const int CYCLE_MILLISECONDS = 100; cDeadlockDetect::cDeadlockDetect(void) : - super("DeadlockDetect") + super("DeadlockDetect"), + m_IntervalSec(1000) { } @@ -136,6 +137,7 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age) void cDeadlockDetect::DeadlockDetected(void) { + LOGERROR("Deadlock detected, aborting the server"); ASSERT(!"Deadlock detected"); abort(); } diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 6fc371958..71154dff9 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -166,6 +166,9 @@ cCaveTunnel::cCaveTunnel( if ((a_BlockStartY <= 0) && (a_BlockEndY <= 0)) { // Don't bother detailing this cave, it's under the world anyway + m_MinBlockX = m_MaxBlockX = 0; + m_MinBlockY = m_MaxBlockY = -1; + m_MinBlockZ = m_MaxBlockZ = 0; return; } diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 3d5af152c..a1188f984 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -27,6 +27,7 @@ const unsigned int QUEUE_SKIP_LIMIT = 500; cChunkGenerator::cChunkGenerator(void) : super("cChunkGenerator"), + m_Seed(0), // Will be overwritten by the actual generator m_Generator(NULL), m_PluginInterface(NULL), m_ChunkSink(NULL) diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index c3f3b38a9..79d529a6a 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -239,7 +239,13 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel cHeiGenClassic::cHeiGenClassic(int a_Seed) : m_Seed(a_Seed), - m_Noise(a_Seed) + m_Noise(a_Seed), + m_HeightFreq1(1.0f), + m_HeightAmp1(1.0f), + m_HeightFreq2(0.5f), + m_HeightAmp2(0.5f), + m_HeightFreq3(0.1f), + m_HeightAmp3(0.1f) { } diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index b9c762e7c..bf46bb241 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -15,7 +15,8 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : m_HTTPServer(a_HTTPServer), m_State(wcsRecvHeaders), - m_CurrentRequest(NULL) + m_CurrentRequest(NULL), + m_CurrentRequestBodyRemaining(0) { // LOGD("HTTP: New connection at %p", this); } diff --git a/src/HTTPServer/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp index 9ddfb82f1..c50c6dcf2 100644 --- a/src/HTTPServer/HTTPFormParser.cpp +++ b/src/HTTPServer/HTTPFormParser.cpp @@ -15,7 +15,9 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks) : m_Callbacks(a_Callbacks), - m_IsValid(true) + m_IsValid(true), + m_IsCurrentPartFile(false), + m_FileHasBeenAnnounced(false) { if (a_Request.GetMethod() == "GET") { @@ -55,7 +57,9 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks) : m_Callbacks(a_Callbacks), m_Kind(a_Kind), - m_IsValid(true) + m_IsValid(true), + m_IsCurrentPartFile(false), + m_FileHasBeenAnnounced(false) { Parse(a_Data, a_Size); } diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index 3fbbee6b5..652b03e46 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -73,6 +73,8 @@ public: HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs) cReader(BLOCKTYPE * a_BlockTypes, HEIGHTTYPE * a_HeightMap) : + m_ReadingChunkX(0), + m_ReadingChunkZ(0), m_MaxHeight(0), m_BlockTypes(a_BlockTypes), m_HeightMap(a_HeightMap) @@ -89,7 +91,9 @@ public: cLightingThread::cLightingThread(void) : super("cLightingThread"), - m_World(NULL) + m_World(NULL), + m_MaxHeight(0), + m_NumSeeds(0) { } diff --git a/src/Noise.cpp b/src/Noise.cpp index 507d05ea5..71e801f30 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -146,6 +146,8 @@ cCubicCell2D::cCubicCell2D( ) : m_Noise(a_Noise), m_WorkRnds(&m_Workspace1), + m_CurFloorX(0), + m_CurFloorY(0), m_Array(a_Array), m_SizeX(a_SizeX), m_SizeY(a_SizeY), @@ -300,6 +302,9 @@ cCubicCell3D::cCubicCell3D( ) : m_Noise(a_Noise), m_WorkRnds(&m_Workspace1), + m_CurFloorX(0), + m_CurFloorY(0), + m_CurFloorZ(0), m_Array(a_Array), m_SizeX(a_SizeX), m_SizeY(a_SizeY), diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index c3074f197..482470c3a 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -16,6 +16,7 @@ cSslContext::cSslContext(void) : m_IsValid(false), m_HasHandshaken(false) { + memset(&m_Ssl, 0, sizeof(m_Ssl)); } diff --git a/src/Server.cpp b/src/Server.cpp index 42ad133f1..cbb9fba4d 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -117,7 +117,9 @@ cServer::cServer(void) : m_MaxPlayers(0), m_bIsHardcore(false), m_TickThread(*this), - m_ShouldAuthenticate(false) + m_ShouldAuthenticate(false), + m_ShouldLoadOfflinePlayerData(false), + m_ShouldLoadNamedPlayerData(true) { } diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index 4ef72e379..ebf99103f 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -76,7 +76,9 @@ public: cFastNBTTag(eTagType a_Type, int a_Parent) : m_Type(a_Type), + m_NameStart(0), m_NameLength(0), + m_DataStart(0), m_DataLength(0), m_Parent(a_Parent), m_PrevSibling(-1), @@ -88,7 +90,9 @@ public: cFastNBTTag(eTagType a_Type, int a_Parent, int a_PrevSibling) : m_Type(a_Type), + m_NameStart(0), m_NameLength(0), + m_DataStart(0), m_DataLength(0), m_Parent(a_Parent), m_PrevSibling(a_PrevSibling), From 8b8ccac0b83decc2b88bedc3bbe50f78ebda6e53 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 22 Aug 2014 10:32:32 +0200 Subject: [PATCH 054/102] ToLua++ lib: Assert when usertype is not known. --- lib/tolua++/src/lib/tolua_push.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/tolua++/src/lib/tolua_push.c b/lib/tolua++/src/lib/tolua_push.c index 947f0e7a5..73a5f6ec0 100644 --- a/lib/tolua++/src/lib/tolua_push.c +++ b/lib/tolua++/src/lib/tolua_push.c @@ -16,6 +16,7 @@ #include "../../../lua/src/lauxlib.h" #include +#include TOLUA_API void tolua_pushvalue (lua_State* L, int lo) { @@ -55,12 +56,14 @@ TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type) else { luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); /* Failure here means that the usertype is unknown to ToLua. Check what type you're pushing. */ lua_pushstring(L,"tolua_ubox"); lua_rawget(L,-2); /* stack: mt ubox */ - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - lua_pushstring(L, "tolua_ubox"); - lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + lua_pushstring(L, "tolua_ubox"); + lua_rawget(L, LUA_REGISTRYINDEX); }; lua_pushlightuserdata(L,value); lua_rawget(L,-2); /* stack: mt ubox ubox[u] */ From 51df169ad58f4712312d0400043cf2094fc9dfd6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 22 Aug 2014 10:33:15 +0200 Subject: [PATCH 055/102] cLuaState: Fixed Vector3<> names pushed to Lua. --- src/Bindings/LuaState.cpp | 46 ++++++++++++++++++++++++++++++++++----- src/Bindings/LuaState.h | 3 +++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index e123a87c9..9fe93ccc2 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -460,7 +460,43 @@ void cLuaState::Push(const Vector3d & a_Vector) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, (void *)&a_Vector, "Vector3d"); + tolua_pushusertype(m_LuaState, (void *)&a_Vector, "Vector3"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::Push(const Vector3d * a_Vector) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, (void *)a_Vector, "Vector3"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::Push(const Vector3i & a_Vector) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, (void *)&a_Vector, "Vector3"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::Push(const Vector3i * a_Vector) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, (void *)a_Vector, "Vector3"); m_NumCurrentFunctionArgs += 1; } @@ -708,11 +744,11 @@ void cLuaState::Push(TakeDamageInfo * a_TDI) -void cLuaState::Push(Vector3i * a_Vector) +void cLuaState::Push(Vector3d * a_Vector) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_Vector, "Vector3i"); + tolua_pushusertype(m_LuaState, a_Vector, "Vector3"); m_NumCurrentFunctionArgs += 1; } @@ -720,11 +756,11 @@ void cLuaState::Push(Vector3i * a_Vector) -void cLuaState::Push(Vector3d * a_Vector) +void cLuaState::Push(Vector3i * a_Vector) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_Vector, "Vector3d"); + tolua_pushusertype(m_LuaState, a_Vector, "Vector3"); m_NumCurrentFunctionArgs += 1; } diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index afac77ce8..eeb93fd4d 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -186,6 +186,9 @@ public: void Push(const HTTPRequest * a_Request); void Push(const HTTPTemplateRequest * a_Request); void Push(const Vector3d & a_Vector); + void Push(const Vector3d * a_Vector); + void Push(const Vector3i & a_Vector); + void Push(const Vector3i * a_Vector); // Push a value onto the stack (keep alpha-sorted): void Push(bool a_Value); From 2dfcd678c41f0066ff69ea39d9dc4bdbfe8ab621 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 22 Aug 2014 10:33:53 +0200 Subject: [PATCH 056/102] Fixed cPlugin::OnPlayerMoving signature. --- src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 2 +- src/Bindings/PluginLua.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 53d4be29d..c9a53346d 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -73,7 +73,7 @@ public: virtual bool OnPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel) = 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 OnPlayerMoving (cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) = 0; + virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; virtual bool OnPlayerPlacedBlock (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 OnPlayerPlacingBlock (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 OnPlayerRightClick (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; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index ad8528114..2c2d05547 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -835,7 +835,7 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block -bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) +bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) { cCSLock Lock(m_CriticalSection); bool res = false; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 2b7358043..eda65b76c 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -98,8 +98,8 @@ public: virtual bool OnPlayerFishing (cPlayer & a_Player, cItems & a_Reward) override; virtual bool OnPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel) override; virtual bool OnPlayerJoined (cPlayer & a_Player) override; - virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) override; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override; + virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) override; virtual bool OnPlayerPlacedBlock (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 OnPlayerPlacingBlock (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 OnPlayerRightClick (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; From d2d63b8a055409d0d07c57fd69b27469fe1681ac Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 22 Aug 2014 10:35:51 +0200 Subject: [PATCH 057/102] World: Report chunk count for the spawn area. --- src/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/World.cpp b/src/World.cpp index d7fa7e0d1..69d1217f1 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -437,7 +437,7 @@ void cWorld::InitializeSpawn(void) int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); IniFile.WriteFile(m_IniFileName); - LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str()); + LOG("Preparing spawn area in world \"%s\", %d x %d chunks, total %d chunks...", m_WorldName.c_str(), ViewDist, ViewDist, ViewDist * ViewDist); for (int x = 0; x < ViewDist; x++) { for (int z = 0; z < ViewDist; z++) From 33b595253209cefcf2bda42ab227b84fad6c600f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 22 Aug 2014 11:12:44 +0200 Subject: [PATCH 058/102] Fixed a warning in FastRandom. --- src/FastRandom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FastRandom.h b/src/FastRandom.h index 2061a3958..cebebad96 100644 --- a/src/FastRandom.h +++ b/src/FastRandom.h @@ -45,7 +45,7 @@ public: float NextFloat(float a_Range, int a_Salt); /** Returns a random float between 0 and 1. */ - float NextFloat(void) { return NextFloat(1); }; + float NextFloat(void) { return NextFloat(1); } /** Returns a random int in the range [a_Begin .. a_End] */ int GenerateRandomInteger(int a_Begin, int a_End); From 8fa4ac9ad957d951cf25c668ffbb4e5d2fafa7f7 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 22 Aug 2014 15:32:27 +0200 Subject: [PATCH 059/102] Fixed item drop. Fixes #1341 --- src/ClientHandle.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index ee4fdfa7d..8aa883144 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -922,11 +922,16 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB return; } - // Check for clickthrough-blocks: - /* When the user breaks a fire block, the client send the wrong block location. - We must find the right block with the face direction. */ - if (a_BlockFace != BLOCK_FACE_NONE) + if ((a_Status == DIG_STATUS_STARTED) || (a_Status == DIG_STATUS_FINISHED)) { + if (a_BlockFace == BLOCK_FACE_NONE) + { + return; + } + + /* Check for clickthrough-blocks: + When the user breaks a fire block, the client send the wrong block location. + We must find the right block with the face direction. */ int BlockX = a_BlockX; int BlockY = a_BlockY; int BlockZ = a_BlockZ; @@ -937,17 +942,16 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB a_BlockY = BlockY; a_BlockZ = BlockZ; } - } - if ( - ((a_Status == DIG_STATUS_STARTED) || (a_Status == DIG_STATUS_FINISHED)) && // Only do a radius check for block destruction - things like pickup tossing send coordinates that are to be ignored - ((Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || - (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) || - (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)) - ) - { - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - return; + if ( + ((Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || + (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) || + (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)) + ) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + return; + } } cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); From 0daacd14d9ab678c08c45a1a1562d5ec160a3ff3 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 23 Aug 2014 03:44:04 +0200 Subject: [PATCH 060/102] RankMgr: Implemented default rank, added defaults. --- MCServer/Plugins/Core | 2 +- src/RankManager.cpp | 200 +++++++++++++++++++++++++++++++++++++----- src/RankManager.h | 22 ++++- 3 files changed, 199 insertions(+), 25 deletions(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 6627e570a..7cc99285a 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 6627e570a5265ae270aae978a1cad80dfb8a2b18 +Subproject commit 7cc99285ae5117418f657c3b295ca71f2b75b4f4 diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 349582950..0cee7724b 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -7,6 +7,7 @@ #include "RankManager.h" #include "inifile/iniFile.h" #include "Protocol/MojangAPI.h" +#include "ClientHandle.h" @@ -54,6 +55,9 @@ public: LOGD("Setting ranks..."); SetRanks(); + + LOGD("Creating defaults..."); + CreateDefaults(); return true; } @@ -87,8 +91,11 @@ protected: AString m_Name; AStringVector m_Groups; - /** Assigned by ResolveUserUUIDs() */ + /** Assigned by ResolveUserUUIDs(), contains the online (Mojang) UUID of the player. */ AString m_UUID; + + /** Assigned by ResolveUserUUIDs(), contains the offline (generated) UUID of the player. */ + AString m_OfflineUUID; sUser(void) {} @@ -275,22 +282,15 @@ protected: m_MojangAPI.GetUUIDsFromPlayerNames(PlayerNames); // Assign the UUIDs back to players, remove those not resolved: - for (sUserMap::iterator itr = m_Users.begin(); itr != m_Users.end(); ) + for (sUserMap::iterator itr = m_Users.begin(); itr != m_Users.end(); ++itr) { AString UUID = m_MojangAPI.GetUUIDFromPlayerName(itr->second.m_Name); if (UUID.empty()) { - LOGWARNING("RankMigrator: Cannot resolve player %s to UUID, player will be left unranked", itr->second.m_Name.c_str()); - sUserMap::iterator itr2 = itr; - ++itr2; - m_Users.erase(itr); - itr = itr2; - } - else - { - itr->second.m_UUID = UUID; - ++itr; + LOGWARNING("RankMigrator: Cannot resolve player %s to online UUID, player will be left unranked in online mode", itr->second.m_Name.c_str()); } + itr->second.m_UUID = UUID; + itr->second.m_OfflineUUID = cClientHandle::GenerateOfflineUUID(itr->second.m_Name); } } @@ -350,10 +350,28 @@ protected: AddGroupsToRank(Groups, RankName); } - // Set the rank to the user: - m_RankManager.SetPlayerRank(itr->second.m_UUID, itr->second.m_Name, RankName); + // Set the rank to the user, using both the online and offline UUIDs: + m_RankManager.SetPlayerRank(itr->second.m_UUID, itr->second.m_Name, RankName); + m_RankManager.SetPlayerRank(itr->second.m_OfflineUUID, itr->second.m_Name, RankName); } // for itr - m_Users[] } + + + + /** Creates the Default rank that contains the Default group, if it exists. + Sets the RankManager's default rank. */ + void CreateDefaults(void) + { + if (!m_RankManager.RankExists("Default")) + { + m_RankManager.AddRank("Default", "", "", ""); + if (!m_RankManager.IsGroupInRank("Default", "Default")) + { + m_RankManager.AddGroupToRank("Default", "Default"); + } + } + m_RankManager.SetDefaultRank("Default"); + } }; @@ -396,6 +414,7 @@ void cRankManager::Initialize(cMojangAPI & a_MojangAPI) m_DB.exec("CREATE TABLE IF NOT EXISTS PermGroup (PermGroupID INTEGER PRIMARY KEY, Name)"); m_DB.exec("CREATE TABLE IF NOT EXISTS RankPermGroup (RankID INTEGER, PermGroupID INTEGER)"); m_DB.exec("CREATE TABLE IF NOT EXISTS PermissionItem (PermGroupID INTEGER, Permission)"); + m_DB.exec("CREATE TABLE IF NOT EXISTS DefaultRank (RankID INTEGER)"); m_IsInitialized = true; @@ -410,12 +429,39 @@ void cRankManager::Initialize(cMojangAPI & a_MojangAPI) if (Migrator.Migrate()) { LOGINFO("Ranks migrated."); + // The default rank has been set by the migrator return; } + + // Migration failed. Add some defaults + LOGINFO("Rank migration failed, creating default ranks..."); + CreateDefaults(); + LOGINFO("Default ranks created."); } - // Migration failed. - // TODO: Check if tables empty, add some defaults then + // Load the default rank: + try + { + SQLite::Statement stmt(m_DB, + "SELECT Rank.Name FROM Rank " + "LEFT JOIN DefaultRank ON Rank.RankID = DefaultRank.RankID" + ); + if (stmt.executeStep()) + { + m_DefaultRank = stmt.getColumn(0).getText(); + } + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Cannot load default rank: %s", __FUNCTION__, ex.what()); + return; + } + + // If the default rank cannot be loaded, use the first rank: + if (m_DefaultRank.empty()) + { + SetDefaultRank(GetAllRanks()[0]); + } } @@ -1085,6 +1131,13 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl { ASSERT(m_IsInitialized); cCSLock Lock(m_CS); + + // Check if the default rank is being removed with a proper replacement: + if ((a_RankName == m_DefaultRank) && !RankExists(a_ReplacementRankName)) + { + LOGWARNING("%s: Cannot remove rank %s, it is the default rank and the replacement rank doesn't exist.", __FUNCTION__, a_RankName.c_str()); + return; + } AStringVector res; try @@ -1143,6 +1196,12 @@ void cRankManager::RemoveRank(const AString & a_RankName, const AString & a_Repl stmt.bind(1, RemoveRankID); stmt.exec(); } + + // Update the default rank, if it was the one being removed: + if (a_RankName == m_DefaultRank) + { + m_DefaultRank = a_RankName; + } } catch (const SQLite::Exception & ex) { @@ -1310,21 +1369,30 @@ bool cRankManager::RenameRank(const AString & a_OldName, const AString & a_NewNa stmt.bind(1, a_NewName); if (stmt.executeStep()) { - LOGD("%s: Rank %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str()); + LOGINFO("%s: Rank %s is already present, cannot rename %s", __FUNCTION__, a_NewName.c_str(), a_OldName.c_str()); return false; } } // Rename: - bool res; { SQLite::Statement stmt(m_DB, "UPDATE Rank SET Name = ? WHERE Name = ?"); stmt.bind(1, a_NewName); stmt.bind(2, a_OldName); - res = (stmt.exec() > 0); + if (stmt.exec() <= 0) + { + LOGINFO("%s: There is no rank %s, cannot rename to %s.", __FUNCTION__, a_OldName.c_str(), a_NewName.c_str()); + return false; + } } - return res; + // Update the default rank, if it was the one being renamed: + if (a_OldName == m_DefaultRank) + { + m_DefaultRank = a_NewName; + } + + return true; } catch (const SQLite::Exception & ex) { @@ -1692,6 +1760,57 @@ void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const AString & +bool cRankManager::SetDefaultRank(const AString & a_RankName) +{ + ASSERT(m_IsInitialized); + cCSLock Lock(m_CS); + + try + { + // Find the rank's ID: + int RankID = 0; + { + SQLite::Statement stmt(m_DB, "SELECT RankID FROM Rank WHERE Name = ?"); + stmt.bind(1, a_RankName); + if (!stmt.executeStep()) + { + LOGINFO("%s: Cannot set rank %s as the default, it does not exist.", __FUNCTION__, a_RankName.c_str()); + return false; + } + } + + // Set the rank as the default: + { + SQLite::Statement stmt(m_DB, "UPDATE DefaultRank SET RankID = ?"); + stmt.bind(1, RankID); + if (stmt.exec() < 1) + { + // Failed to update, there might be none in the DB, try inserting: + SQLite::Statement stmt2(m_DB, "INSERT INTO DefaultRank (RankID) VALUES (?)"); + stmt2.bind(1, RankID); + if (stmt2.exec() < 1) + { + LOGINFO("%s: Cannot update the default rank in the DB to %s.", __FUNCTION__, a_RankName.c_str()); + return false; + } + } + } + + // Set the internal cache: + m_DefaultRank = a_RankName; + return true; + } + catch (const SQLite::Exception & ex) + { + LOGWARNING("%s: Failed to update DB: %s", __FUNCTION__, ex.what()); + return false; + } +} + + + + + bool cRankManager::AreDBTablesEmpty(void) { return ( @@ -1699,7 +1818,8 @@ bool cRankManager::AreDBTablesEmpty(void) IsDBTableEmpty("PlayerRank") && IsDBTableEmpty("PermGroup") && IsDBTableEmpty("RankPermGroup") && - IsDBTableEmpty("PermissionItem") + IsDBTableEmpty("PermissionItem") && + IsDBTableEmpty("DefaultRank") ); } @@ -1724,3 +1844,41 @@ bool cRankManager::IsDBTableEmpty(const AString & a_TableName) + +void cRankManager::CreateDefaults(void) +{ + // Wrap everything in a big transaction to speed things up: + cMassChangeLock Lock(*this); + + // Create ranks: + AddRank("Default", "", "", ""); + AddRank("VIP", "", "", ""); + AddRank("Operator", "", "", ""); + AddRank("Admin", "", "", ""); + + // Create groups: + AddGroup("Default"); + AddGroup("Kick"); + AddGroup("Teleport"); + AddGroup("Everything"); + + // Add groups to ranks: + AddGroupToRank("Default", "Default"); + AddGroupToRank("Teleport", "VIP"); + AddGroupToRank("Teleport", "Operator"); + AddGroupToRank("Kick", "Operator"); + AddGroupToRank("Everything", "Admin"); + + // Add permissions to groups: + AddPermissionToGroup("core.build", "Default"); + AddPermissionToGroup("core.tp", "Teleport"); + AddPermissionToGroup("core.kick", "Kick"); + AddPermissionToGroup("*", "Everything"); + + // Set the default rank: + SetDefaultRank("Default"); +} + + + + diff --git a/src/RankManager.h b/src/RankManager.h index 24030ef22..b93a1157d 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -127,7 +127,9 @@ public: /** Removes the specified rank. All players assigned to that rank will be re-assigned to a_ReplacementRankName. If a_ReplacementRankName is empty or not a valid rank, the player will be removed from the DB, - which means they will receive the default rank the next time they are queried. */ + which means they will receive the default rank the next time they are queried. + If the rank being removed is the default rank, the default will be changed to the replacement + rank; the operation fails if there's no replacement. */ void RemoveRank(const AString & a_RankName, const AString & a_ReplacementRankName); /** Removes the specified group completely. @@ -143,6 +145,7 @@ public: /** Renames the specified rank. No action if the rank name is not found. Fails if the new name is already used. + Updates the cached m_DefaultRank if the default rank is being renamed. Returns true on success, false on failure. */ bool RenameRank(const AString & a_OldName, const AString & a_NewName); @@ -198,13 +201,23 @@ public: /** Called by cMojangAPI whenever the playername-uuid pairing is discovered. Updates the DB. */ void NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID); - + + /** Sets the specified rank as the default rank. + Returns true on success, false on failure (rank not found). */ + bool SetDefaultRank(const AString & a_RankName); + + /** Returns the name of the default rank. */ + const AString & GetDefaultRank(void) const { return m_DefaultRank; } + protected: /** The database storage for all the data. Protected by m_CS. */ SQLite::Database m_DB; - /** The mutex protecting m_DB against multi-threaded access. */ + /** The name of the default rank. Kept as a cache so that queries for it don't need to go through the DB. */ + AString m_DefaultRank; + + /** The mutex protecting m_DB and m_DefaultRank against multi-threaded access. */ cCriticalSection m_CS; /** Set to true once the manager is initialized. */ @@ -221,6 +234,9 @@ protected: /** Returns true iff the specified DB table is empty. If there's an error while querying, returns false. */ bool IsDBTableEmpty(const AString & a_TableName); + + /** Creates a default set of ranks / groups / permissions. */ + void CreateDefaults(void); } ; From d07134e6212ea39f0d23c7edcfb22573d5b58b77 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Sat, 23 Aug 2014 16:06:34 +0100 Subject: [PATCH 061/102] Assume POWER is big-endian, so it compiles. [reference](http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros#POWER) We may want to come back and figure out if the processor is running in little-endian mode, but for now assume they're big-endian. --- src/ByteBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 64b31c60b..96556bf61 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -27,7 +27,7 @@ ) #define IS_LITTLE_ENDIAN #elif ( \ - defined (__ARMEB__) || defined(__sparc) \ + defined (__ARMEB__) || defined(__sparc) || defined(__powerpc__) || defined(__POWERPC__) \ ) #define IS_BIG_ENDIAN #else From da67dd39ed965f134e480fe11cdf140fbd9a9df2 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 23 Aug 2014 17:56:23 +0200 Subject: [PATCH 062/102] RankMgr: Unified function signature comments in the bindings. --- src/Bindings/ManualBindings.h | 1 - src/Bindings/ManualBindings_RankManager.cpp | 63 ++++++++++++--------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index 0302b9503..1b6e65654 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -6,7 +6,6 @@ struct lua_State; - /** Provides namespace for the bindings. */ class ManualBindings { diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index 5351c028d..f25f87e46 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -16,6 +16,9 @@ /** Binds cRankManager::AddGroup */ static int tolua_cRankManager_AddGroup(lua_State * L) { + // Function signature: + // cRankManager:AddGroup(GroupName) + cLuaState S(L); if ( !S.CheckParamUserTable(1, "cRankManager") || @@ -39,9 +42,12 @@ static int tolua_cRankManager_AddGroup(lua_State * L) -/** Binds cRankManager::AddGroup */ +/** Binds cRankManager::AddGroupToRank */ static int tolua_cRankManager_AddGroupToRank(lua_State * L) { + // Function signature: + // cRankManager:AddGroupToRank(GroupName, RankName) -> bool + cLuaState S(L); if ( !S.CheckParamUserTable(1, "cRankManager") || @@ -68,6 +74,9 @@ static int tolua_cRankManager_AddGroupToRank(lua_State * L) /** Binds cRankManager::AddPermissionToGroup */ static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) { + // Function signature: + // cRankManager:AddPermissionToGroup(Permission, GroupName) -> bool + cLuaState S(L); if ( !S.CheckParamUserTable(1, "cRankManager") || @@ -94,7 +103,7 @@ static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) /** Binds cRankManager::AddRank */ static int tolua_cRankManager_AddRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:AddRank(RankName) cLuaState S(L); @@ -123,7 +132,7 @@ static int tolua_cRankManager_AddRank(lua_State * L) /** Binds cRankManager::GetAllGroups */ static int tolua_cRankManager_GetAllGroups(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetAllGroups() -> arraytable of GroupNames cLuaState S(L); @@ -150,7 +159,7 @@ static int tolua_cRankManager_GetAllGroups(lua_State * L) /** Binds cRankManager::GetAllPermissions */ static int tolua_cRankManager_GetAllPermissions(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetAllPermissions() -> arraytable of Permissions cLuaState S(L); @@ -177,7 +186,7 @@ static int tolua_cRankManager_GetAllPermissions(lua_State * L) /** Binds cRankManager::GetAllRanks */ static int tolua_cRankManager_GetAllRanks(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetAllRanks() -> arraytable of RankNames cLuaState S(L); @@ -204,7 +213,7 @@ static int tolua_cRankManager_GetAllRanks(lua_State * L) /** Binds cRankManager::GetGroupPermissions */ static int tolua_cRankManager_GetGroupPermissions(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetGroupPermissions(GroupName) -> arraytable of permissions cLuaState S(L); @@ -236,7 +245,7 @@ static int tolua_cRankManager_GetGroupPermissions(lua_State * L) /** Binds cRankManager::GetPlayerGroups */ static int tolua_cRankManager_GetPlayerGroups(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetPlayerGroups(PlayerUUID) -> arraytable of GroupNames cLuaState S(L); @@ -268,7 +277,7 @@ static int tolua_cRankManager_GetPlayerGroups(lua_State * L) /** Binds cRankManager::GetPlayerMsgVisuals */ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetPlayerMsgVisuals(PlayerUUID) -> string, string, string cLuaState S(L); @@ -306,7 +315,7 @@ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L) /** Binds cRankManager::GetPlayerPermissions */ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetPlayerPermissions(PlayerUUID) -> arraytable of permissions cLuaState S(L); @@ -338,7 +347,7 @@ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L) /** Binds cRankManager::GetPlayerRankName */ static int tolua_cRankManager_GetPlayerRankName(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetPlayerRankName(PlayerUUID) -> string cLuaState S(L); @@ -370,7 +379,7 @@ static int tolua_cRankManager_GetPlayerRankName(lua_State * L) /** Binds cRankManager::GetRankGroups */ static int tolua_cRankManager_GetRankGroups(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetRankGroups(RankName) -> arraytable of groupnames cLuaState S(L); @@ -402,7 +411,7 @@ static int tolua_cRankManager_GetRankGroups(lua_State * L) /** Binds cRankManager::GetRankPermissions */ static int tolua_cRankManager_GetRankPermissions(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetRankPermissions(RankName) -> arraytable of permissions cLuaState S(L); @@ -434,7 +443,7 @@ static int tolua_cRankManager_GetRankPermissions(lua_State * L) /** Binds cRankManager::GetRankVisuals */ static int tolua_cRankManager_GetRankVisuals(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GetRankVisuals(RankName) -> MsgPrefix, MsgSuffix, MsgNameColorCode cLuaState S(L); @@ -473,7 +482,7 @@ static int tolua_cRankManager_GetRankVisuals(lua_State * L) /** Binds cRankManager::GroupExists */ static int tolua_cRankManager_GroupExists(lua_State * L) { - // function signature: + // Function signature: // cRankManager:GroupExists(GroupName) -> bool cLuaState S(L); @@ -505,7 +514,7 @@ static int tolua_cRankManager_GroupExists(lua_State * L) /** Binds cRankManager::IsGroupInRank */ static int tolua_cRankManager_IsGroupInRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:IsGroupInRank(GroupName, RankName) -> bool cLuaState S(L); @@ -537,7 +546,7 @@ static int tolua_cRankManager_IsGroupInRank(lua_State * L) /** Binds cRankManager::IsPermissionInGroup */ static int tolua_cRankManager_IsPermissionInGroup(lua_State * L) { - // function signature: + // Function signature: // cRankManager:IsPermissionInGroup(Permission, GroupName) -> bool cLuaState S(L); @@ -569,7 +578,7 @@ static int tolua_cRankManager_IsPermissionInGroup(lua_State * L) /** Binds cRankManager::IsPlayerRankSet */ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L) { - // function signature: + // Function signature: // cRankManager:IsPlayerRankSet(PlayerUUID) -> bool cLuaState S(L); @@ -601,7 +610,7 @@ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L) /** Binds cRankManager::RankExists */ static int tolua_cRankManager_RankExists(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RankExists(RankName) -> bool cLuaState S(L); @@ -633,7 +642,7 @@ static int tolua_cRankManager_RankExists(lua_State * L) /** Binds cRankManager::RemoveGroup */ static int tolua_cRankManager_RemoveGroup(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RemoveGroup(GroupName) cLuaState S(L); @@ -662,7 +671,7 @@ static int tolua_cRankManager_RemoveGroup(lua_State * L) /** Binds cRankManager::RemoveGroupFromRank */ static int tolua_cRankManager_RemoveGroupFromRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RemoveGroupFromRank(GroupName, RankName) cLuaState S(L); @@ -691,7 +700,7 @@ static int tolua_cRankManager_RemoveGroupFromRank(lua_State * L) /** Binds cRankManager::RemovePermissionFromGroup */ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RemovePermissionFromGroup(Permission, GroupName) cLuaState S(L); @@ -720,7 +729,7 @@ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) /** Binds cRankManager::RemovePlayerRank */ static int tolua_cRankManager_RemovePlayerRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RemovePlayerRank(PlayerUUID) cLuaState S(L); @@ -749,7 +758,7 @@ static int tolua_cRankManager_RemovePlayerRank(lua_State * L) /** Binds cRankManager::RemoveRank */ static int tolua_cRankManager_RemoveRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RemoveRank(RankName, [ReplacementRankName]) cLuaState S(L); @@ -779,7 +788,7 @@ static int tolua_cRankManager_RemoveRank(lua_State * L) /** Binds cRankManager::RenameGroup */ static int tolua_cRankManager_RenameGroup(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RenameGroup(OldName, NewName) cLuaState S(L); @@ -811,7 +820,7 @@ static int tolua_cRankManager_RenameGroup(lua_State * L) /** Binds cRankManager::RenameRank */ static int tolua_cRankManager_RenameRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:RenameRank(OldName, NewName) cLuaState S(L); @@ -843,7 +852,7 @@ static int tolua_cRankManager_RenameRank(lua_State * L) /** Binds cRankManager::SetPlayerRank */ static int tolua_cRankManager_SetPlayerRank(lua_State * L) { - // function signature: + // Function signature: // cRankManager:SetPlayerRank(PlayerUUID, PlayerName, RankName) cLuaState S(L); @@ -872,7 +881,7 @@ static int tolua_cRankManager_SetPlayerRank(lua_State * L) /** Binds cRankManager::SetRankVisuals */ static int tolua_cRankManager_SetRankVisuals(lua_State * L) { - // function signature: + // Function signature: // cRankManager:SetRankVisuals(RankName, MsgPrefix, MsgSuffix, MsgNameColorCode) cLuaState S(L); From a56634799e1fb7eef3d2817bd7d9c1b42969e934 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Sun, 24 Aug 2014 15:03:02 +0200 Subject: [PATCH 063/102] Change comment formatting --- src/Entities/Minecart.cpp | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 13469edb3..f43c4d163 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -889,35 +889,31 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) ((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) <= 1)) ) - // Moving -X +Z { + // Moving -X +Z if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) - // ~ speedX >= 0 { - // Immobile or not moving in the "right" direction. Give it a bump! + // ~ SpeedX >= 0 Immobile or not moving in the "right" direction. Give it a bump! AddSpeedX(-4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } else - // ~ SpeedX < 0 { - // Moving in the "right" direction. Only accelerate it a bit. + // ~ SpeedX < 0 Moving in the "right" direction. Only accelerate it a bit. SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } } else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) - // Moving +X -Z - // ~ SpeedX <= 0 { - // Immobile or not moving in the "right" direction + // Moving +X -T + // ~ SpeedX <= 0 Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } else - // ~ SpeedX > 0 { - // Moving in the "right" direction + // ~ SpeedX > 0 Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } @@ -942,35 +938,31 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) ((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) || ((Distance.z < 0) && ((Distance.x / Distance.z) >= -1)) ) - // Moving +X +Z { + // Moving +X +Z if ((GetSpeedX() * 0.4) < 0.01) - // ~ SpeedX <= 0 { - // Immobile or not moving in the "right" direction + // ~ SpeedX <= 0 Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(4 / sqrt(2)); } else - // SpeedX > 0 { - // Moving in the "right" direction + // ~ SpeedX > 0 Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } } else if ((-GetSpeedX() * 0.4) < 0.01) - // Moving -X -Z - // ~ SpeedX >= 0 { - // Immobile or not moving in the "right" direction + // Moving -X -Z + // ~ SpeedX >= 0 Immobile or not moving in the "right" direction AddSpeedX(-4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); } else - // ~ SpeedX < 0 { - // Moving in the "right" direction + // ~ SpeedX < 0 Moving in the "right" direction SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); } From 8630b20c523033b359e4f9d7513cb6e4aafec1cb Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 24 Aug 2014 20:00:45 +0200 Subject: [PATCH 064/102] RankMgr: Default rank is applied to players without any rank. --- src/Entities/Player.cpp | 6 +++- src/RankManager.cpp | 69 +++++++---------------------------------- src/RankManager.h | 6 ++-- 3 files changed, 21 insertions(+), 60 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 7992204da..b0dd40615 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -2051,8 +2051,12 @@ void cPlayer::LoadRank(void) // Load the values from cRankManager: cRankManager & RankMgr = cRoot::Get()->GetRankManager(); m_Rank = RankMgr.GetPlayerRankName(m_UUID); + if (m_Rank.empty()) + { + m_Rank = RankMgr.GetDefaultRank(); + } m_Permissions = RankMgr.GetPlayerPermissions(m_UUID); - RankMgr.GetPlayerMsgVisuals(m_UUID, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); + RankMgr.GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); // Break up the individual permissions on each dot, into m_SplitPermissions: m_SplitPermissions.clear(); diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 0cee7724b..65ce33b92 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -534,34 +534,12 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID) { - ASSERT(m_IsInitialized); - cCSLock Lock(m_CS); - - AStringVector res; - try + AString Rank = GetPlayerRankName(a_PlayerUUID); + if (Rank.empty()) { - // Prepare the DB statement: - SQLite::Statement stmt(m_DB, - "SELECT DISTINCT(PermissionItem.Permission) FROM PermissionItem " - "LEFT JOIN RankPermGroup " - "ON PermissionItem.PermGroupID = RankPermGroup.PermGroupID " - "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankPermGroup.RankID " - "WHERE PlayerRank.PlayerUUID = ?" - ); - stmt.bind(1, a_PlayerUUID); - - // Execute and get results: - while (stmt.executeStep()) - { - res.push_back(stmt.getColumn(0).getText()); - } + Rank = m_DefaultRank; } - catch (const SQLite::Exception & ex) - { - LOGWARNING("%s: Cannot get player permissions: %s", __FUNCTION__, ex.what()); - } - return res; + return GetRankPermissions(Rank); } @@ -742,39 +720,16 @@ bool cRankManager::GetPlayerMsgVisuals( AString & a_MsgNameColorCode ) { - ASSERT(m_IsInitialized); - cCSLock Lock(m_CS); - - AStringVector res; - try + AString Rank = GetPlayerRankName(a_PlayerUUID); + if (Rank.empty()) { - SQLite::Statement stmt(m_DB, - "SELECT Rank.MsgPrefix, Rank.MsgSuffix, Rank.MsgNameColorCode FROM Rank " - "LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID " - "WHERE PlayerRank.PlayerUUID = ?" - ); - stmt.bind(1, a_PlayerUUID); - if (!stmt.executeStep()) - { - LOGD("%s: Player UUID %s not found in the DB, returning empty values.", __FUNCTION__, a_PlayerUUID.c_str()); - a_MsgPrefix.clear(); - a_MsgSuffix.clear(); - a_MsgNameColorCode.clear(); - return false; - } - a_MsgPrefix = stmt.getColumn(0).getText(); - a_MsgSuffix = stmt.getColumn(1).getText(); - a_MsgNameColorCode = stmt.getColumn(2).getText(); - return true; + // Rank not found, return failure: + a_MsgPrefix.clear(); + a_MsgSuffix.clear(); + a_MsgNameColorCode.clear(); + return false; } - catch (const SQLite::Exception & ex) - { - LOGWARNING("%s: Failed to get ranks from DB: %s. Returning empty values.", __FUNCTION__, ex.what()); - } - a_MsgPrefix.clear(); - a_MsgSuffix.clear(); - a_MsgNameColorCode.clear(); - return false; + return GetRankVisuals(Rank, a_MsgPrefix, a_MsgSuffix, a_MsgNameColorCode); } diff --git a/src/RankManager.h b/src/RankManager.h index b93a1157d..f364bba6a 100644 --- a/src/RankManager.h +++ b/src/RankManager.h @@ -56,13 +56,15 @@ public: The a_MojangAPI param is used when migrating from old ini files, to look up player UUIDs. */ void Initialize(cMojangAPI & a_MojangAPI); - /** Returns the name of the rank that the specified player has assigned to them. */ + /** Returns the name of the rank that the specified player has assigned to them. + If the player has no rank assigned, returns an empty string (NOT the default rank). */ AString GetPlayerRankName(const AString & a_PlayerUUID); /** Returns the names of Groups that the specified player has assigned to them. */ AStringVector GetPlayerGroups(const AString & a_PlayerUUID); - /** Returns the permissions that the specified player has assigned to them. */ + /** Returns the permissions that the specified player has assigned to them. + If the player has no rank assigned to them, returns the default rank's permissions. */ AStringVector GetPlayerPermissions(const AString & a_PlayerUUID); /** Returns the names of groups that the specified rank has assigned to it. From 3977d53b8301108c4b121467647ddd6e2f2ddaea Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 24 Aug 2014 20:05:28 +0200 Subject: [PATCH 065/102] RankMgr: Exported the default-rank functions. --- MCServer/Plugins/APIDump/APIDesc.lua | 20 +++++--- src/Bindings/ManualBindings_RankManager.cpp | 55 +++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 6138f945a..fe56ecee8 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2003,7 +2003,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);

Permissions are added to individual groups. Each group can support unlimited permissions. Note that adding a permission to a group will make the permission available to all the ranks that contain that - permission group. + permission group.

+

+ One rank is reserved as the Default rank. All players that don't have an explicit rank assigned to them + will behave as if assigned to this rank. The default rank can be changed to any other rank at any time. + Note that the default rank cannot be removed from the RankManager - RemoveRank() will change the default + rank to the replacement rank, if specified, and fail if no replacement rank is specified. Renaming the + default rank using RenameRank() will change the default rank to the new name. ]], Functions = { @@ -2014,11 +2020,12 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); GetAllGroups = { Params = "", Return = "array-table of groups' names", Notes = "Returns an array-table containing the names of all the groups that are known to the manager." }, GetAllPermissions = { Params = "", Return = "array-table of permissions", Notes = "Returns an array-table containing all the permissions that are known to the manager." }, GetAllRanks = { Params = "", Return = "array-table of ranks' names", Notes = "Returns an array-table containing the names of all the ranks that are known to the manager." }, + GetDefaultRank = { Params = "", Return = "string", Notes = "Returns the name of the default rank. " }, GetGroupPermissions = { Params = "GroupName", Return = "array-table of permissions", Notes = "Returns an array-table containing the permissions that the specified group contains." }, GetPlayerGroups = { Params = "PlayerUUID", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of the groups that are assigned to the specified player through their rank. Returns an empty table if the player is not known or has no rank or groups assigned to them." }, - GetPlayerMsgVisuals = { Params = "PlayerUUID", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals assigned to the player. If the player is not known or has no rank assigned, doesn't return any value." }, - GetPlayerPermissions = { Params = "PlayerUUID", Return = "array-table of permissions", Notes = "Returns the permissions that the specified player is assigned through their rank. Returns an empty table if the player is not known." }, - GetPlayerRankName = { Params = "PlayerUUID", Return = "RankName", Notes = "Returns the name of the rank that is assigned to the specified player. An empty string is returned if the player has no rank assigned to them." }, + GetPlayerMsgVisuals = { Params = "PlayerUUID", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals assigned to the player. If the player is not explicitly assigned a rank, the default rank's visuals are returned. If there is an error, no value is returned at all." }, + GetPlayerPermissions = { Params = "PlayerUUID", Return = "array-table of permissions", Notes = "Returns the permissions that the specified player is assigned through their rank. Returns the default rank's permissions if the player has no explicit rank assigned to them. Returns an empty array on error." }, + GetPlayerRankName = { Params = "PlayerUUID", Return = "RankName", Notes = "Returns the name of the rank that is assigned to the specified player. An empty string (NOT the default rank) is returned if the player has no rank assigned to them." }, GetRankGroups = { Params = "RankName", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of all the groups that are assigned to the specified rank. Returns an empty table if there is no such rank." }, GetRankPermissions = { Params = "RankName", Return = "array-table of permissions", Notes = "Returns an array-table of all the permissions that are assigned to the specified rank through its groups. Returns an empty table if there is no such rank." }, GetRankVisuals = { Params = "RankName", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals for the specified rank. Returns no value if the specified rank does not exist." }, @@ -2032,8 +2039,9 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); RemovePermissionFromGroup = { Params = "Permission, GroupName", Return = "", Notes = "Removes the specified permission from the specified group. Logs an info message and does nothing if the group doesn't exist." }, RemovePlayerRank = { Params = "PlayerUUID", Return = "", Notes = "Removes the player's rank; the player's left without a rank. Note that this doesn't change the {{cPlayer}} instances for the already connected players, you need to update all the instances manually. No action if the player has no rank assigned to them already." }, RemoveRank = { Params = "RankName, [ReplacementRankName]", Return = "", Notes = "Removes the specified rank. If ReplacementRankName is given, the players that have RankName will get their rank set to ReplacementRankName. If it isn't given, or is an invalid rank, the players will be removed from the manager, their ranks will be unset completely. Logs an info message and does nothing if the rank is not found." }, - RenameGroup = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified group. Logs an info message and does nothing if the group is not found." }, - RenameRank = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified rank. Logs an info message and does nothing if the rank is not found." }, + RenameGroup = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified group. Logs an info message and does nothing if the group is not found or the new name is already used." }, + RenameRank = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified rank. Logs an info message and does nothing if the rank is not found or the new name is already used." }, + SetDefaultRank = { Params = "RankName", Return = "bool", Notes = "Sets the specified rank as the default rank. Returns true on success, false on failure (rank doesn't exist)." }, SetPlayerRank = { Params = "PlayerUUID, PlayerName, RankName", Return = "", Notes = "Updates the rank for the specified player. The player name is provided for reference, the UUID is used for identification. Logs a warning and does nothing if the rank is not found." }, SetRankVisuals = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Updates the rank's message visuals. Logs an info message and does nothing if rank not found." }, }, diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index f25f87e46..2e93ad264 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -210,6 +210,30 @@ static int tolua_cRankManager_GetAllRanks(lua_State * L) +/** Binds cRankManager::GetDefaultRank */ +static int tolua_cRankManager_GetDefaultRank(lua_State * L) +{ + // Function signature: + // cRankManager:GetDefaultRank() -> string + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Return the rank name: + S.Push(cRoot::Get()->GetRankManager().GetDefaultRank()); + return 1; +} + + + + + /** Binds cRankManager::GetGroupPermissions */ static int tolua_cRankManager_GetGroupPermissions(lua_State * L) { @@ -849,6 +873,35 @@ static int tolua_cRankManager_RenameRank(lua_State * L) +/** Binds cRankManager::SetDefaultRank */ +static int tolua_cRankManager_SetDefaultRank(lua_State * L) +{ + // Function signature: + // cRankManager:SetDefaultRank(RankName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Set the rank, return the result: + S.Push(cRoot::Get()->GetRankManager().SetDefaultRank(RankName)); + return 0; +} + + + + + /** Binds cRankManager::SetPlayerRank */ static int tolua_cRankManager_SetPlayerRank(lua_State * L) { @@ -922,6 +975,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "GetAllGroups", tolua_cRankManager_GetAllGroups); tolua_function(tolua_S, "GetAllPermissions", tolua_cRankManager_GetAllPermissions); tolua_function(tolua_S, "GetAllRanks", tolua_cRankManager_GetAllRanks); + tolua_function(tolua_S, "GetDefaultRank", tolua_cRankManager_GetDefaultRank); tolua_function(tolua_S, "GetGroupPermissions", tolua_cRankManager_GetGroupPermissions); tolua_function(tolua_S, "GetPlayerGroups", tolua_cRankManager_GetPlayerGroups); tolua_function(tolua_S, "GetPlayerMsgVisuals", tolua_cRankManager_GetPlayerMsgVisuals); @@ -942,6 +996,7 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) tolua_function(tolua_S, "RemoveRank", tolua_cRankManager_RemoveRank); tolua_function(tolua_S, "RenameGroup", tolua_cRankManager_RenameGroup); tolua_function(tolua_S, "RenameRank", tolua_cRankManager_RenameRank); + tolua_function(tolua_S, "SetDefaultRank", tolua_cRankManager_SetDefaultRank); tolua_function(tolua_S, "SetPlayerRank", tolua_cRankManager_SetPlayerRank); tolua_function(tolua_S, "SetRankVisuals", tolua_cRankManager_SetRankVisuals); tolua_endmodule(tolua_S); From 8f20c359cd1f1086d4c312273fe052404755584f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 25 Aug 2014 07:28:45 +0200 Subject: [PATCH 066/102] Fixed a type warning. --- src/Protocol/MojangAPI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 823ff5469..d107a8470 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -655,11 +655,11 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) } // Store the returned results into cache: - size_t JsonCount = root.size(); + Json::Value::UInt JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); - for (size_t idx = 0; idx < JsonCount; ++idx) + for (Json::Value::UInt idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); From bf16c5ed92c7d45599099c4c3d628cee1a60f35f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 25 Aug 2014 18:25:39 +0300 Subject: [PATCH 067/102] Type warning fixes. --- src/Inventory.cpp | 2 +- src/Protocol/MojangAPI.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Inventory.cpp b/src/Inventory.cpp index 8da3dea5f..832a079bc 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -106,7 +106,7 @@ int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryT // When the item is a armor, try to set it directly to the armor slot. if (ItemCategory::IsArmor(a_Item.m_ItemType)) { - for (size_t i = 0; i < (size_t)m_ArmorSlots.GetNumSlots(); i++) + for (int i = 0; i < m_ArmorSlots.GetNumSlots(); i++) { if (m_ArmorSlots.GetSlot(i).IsEmpty() && cSlotAreaArmor::CanPlaceArmorInSlot(i, a_Item)) { diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index d107a8470..83c2dc300 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -675,7 +675,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); - for (size_t idx = 0; idx < JsonCount; ++idx) + for (Json::Value::UInt idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); From ac4d3a30ed76a7e139eac02de9edcb9fdbbf7957 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 15:16:33 +0300 Subject: [PATCH 068/102] Added initial dungeon rooms finisher. --- src/Generating/CMakeLists.txt | 2 + src/Generating/ComposableGenerator.cpp | 8 + src/Generating/DungeonRoomsFinisher.cpp | 232 ++++++++++++++++++++++++ src/Generating/DungeonRoomsFinisher.h | 47 +++++ 4 files changed, 289 insertions(+) create mode 100644 src/Generating/DungeonRoomsFinisher.cpp create mode 100644 src/Generating/DungeonRoomsFinisher.h diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt index 58df9d421..33d622b42 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -12,6 +12,7 @@ SET (SRCS CompoGen.cpp ComposableGenerator.cpp DistortedHeightmap.cpp + DungeonRoomsFinisher.cpp EndGen.cpp FinishGen.cpp GridStructGen.cpp @@ -40,6 +41,7 @@ SET (HDRS CompoGen.h ComposableGenerator.h DistortedHeightmap.h + DungeonRoomsFinisher.h EndGen.h FinishGen.h GridStructGen.h diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 2f575fe27..a3a9f170d 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -19,6 +19,7 @@ #include "Caves.h" #include "DistortedHeightmap.h" +#include "DungeonRoomsFinisher.h" #include "EndGen.h" #include "MineShafts.h" #include "NetherFortGen.h" @@ -343,6 +344,13 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3); m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold)); } + else if (NoCaseCompare(*itr, "DungeonRooms") == 0) + { + int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48); + int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7); + int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5); + m_FinishGens.push_back(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize)); + } else if (NoCaseCompare(*itr, "Ice") == 0) { m_FinishGens.push_back(new cFinishGenIce); diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp new file mode 100644 index 000000000..37409d486 --- /dev/null +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -0,0 +1,232 @@ + +// DungeonRoomsFinisher.cpp + +// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms + +#include "Globals.h" +#include "DungeonRoomsFinisher.h" + + + + + +/** Height, in blocks, of the internal dungeon room open space. This many air blocks Y-wise. */ +static const int ROOM_HEIGHT = 4; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cDungeonRoom: + +class cDungeonRoom : + public cGridStructGen::cStructure +{ + typedef cGridStructGen::cStructure super; + +public: + + cDungeonRoom( + int a_GridX, int a_GridZ, + int a_OriginX, int a_OriginZ, + int a_HalfSizeX, int a_HalfSizeZ, + int a_FloorHeight, + cNoise & a_Noise + ) : + super(a_GridX, a_GridZ, a_OriginX, a_OriginZ), + m_StartX(a_OriginX - a_HalfSizeX), + m_EndX(a_OriginX + a_HalfSizeX), + m_StartZ(a_OriginZ - a_HalfSizeZ), + m_EndZ(a_OriginZ + a_HalfSizeZ), + m_FloorHeight(a_FloorHeight), + m_Chest1(SelectChestCoords(a_Noise, a_OriginX + 1, a_OriginZ)), + m_Chest2(SelectChestCoords(a_Noise, a_OriginX + 2, a_OriginZ)) + { + } + +protected: + + // The X range of the room, start inclusive, end exclusive: + int m_StartX, m_EndX; + + // The Z range of the room, start inclusive, end exclusive: + int m_StartZ, m_EndZ; + + /** The Y coord of the floor of the room */ + int m_FloorHeight; + + /** The (absolute) coords of the first chest. The Y coord represents the chest's Meta value (facing). */ + Vector3i m_Chest1; + + /** The (absolute) coords of the second chest. The Y coord represents the chest's Meta value (facing). */ + Vector3i m_Chest2; + + + + /** Selects the coords for the chest, using the noise and coords provided. + Assumes that the room XZ ranges are already assigned. */ + Vector3i SelectChestCoords(cNoise & a_Noise, int a_X, int a_Z) + { + // Pick a coord next to the wall: + int rnd = a_Noise.IntNoise2DInt(a_X, a_Z) / 7; + int SizeX = m_EndX - m_StartX - 1; + int SizeZ = m_EndZ - m_StartZ - 1; + rnd = rnd % (2 * SizeX + 2 * SizeZ); + + if (rnd < SizeX) + { + // Return a coord on the ZM side of the room: + return Vector3i(m_StartX + rnd + 1, E_META_CHEST_FACING_ZP, m_StartZ + 1); + } + rnd -= SizeX; + if (rnd < SizeZ) + { + // Return a coord on the XP side of the room: + return Vector3i(m_EndX - 1, E_META_CHEST_FACING_XM, m_StartZ + rnd + 1); + } + rnd -= SizeZ; + if (rnd < SizeX) + { + // Return a coord on the ZP side of the room: + return Vector3i(m_StartX + rnd + 1, E_META_CHEST_FACING_ZM, m_StartZ + 1); + } + rnd -= SizeX; + // Return a coord on the XM side of the room: + return Vector3i(m_StartX + 1, E_META_CHEST_FACING_XP, m_StartZ + rnd + 1); + } + + + + /** Fills the specified area of blocks in the chunk with the specified blocktype if they are one of the overwritten block types. + The coords are absolute, start coords are inclusive, end coords are exclusive. */ + void ReplaceCuboid(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType) + { + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1); + int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1); + int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width); + int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width); + for (int y = a_StartY; y < a_EndY; y++) + { + for (int z = RelStartZ; z < RelEndZ; z++) + { + for (int x = RelStartX; x < RelEndX; x++) + { + switch (a_ChunkDesc.GetBlockType(x, y, z)) + { + case E_BLOCK_STONE: + case E_BLOCK_DIRT: + case E_BLOCK_GRASS: + case E_BLOCK_GRAVEL: + case E_BLOCK_SAND: + { + a_ChunkDesc.SetBlockType(x, y, z, a_DstBlockType); + break; + } + } // switch (GetBlockType) + } // for x + } // for z + } // for z + } + + + + /** Tries to place a chest at the specified (absolute) coords. + Does nothing if the coords are outside the chunk. */ + void TryPlaceChest(cChunkDesc & a_ChunkDesc, const Vector3i & a_Chest) + { + int RelX = a_Chest.x - a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int RelZ = a_Chest.z - a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + if ( + (RelX < 0) || (RelX >= cChunkDef::Width) || // The X coord is not in this chunk + (RelZ < 0) || (RelZ >= cChunkDef::Width) // The Z coord is not in this chunk + ) + { + return; + } + a_ChunkDesc.SetBlockTypeMeta(RelX, m_FloorHeight + 1, RelZ, E_BLOCK_CHEST, (NIBBLETYPE)a_Chest.y); + + // TODO: Fill the chest with random loot + } + + + + // cGridStructGen::cStructure override: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override + { + if ( + (m_EndX <= a_ChunkDesc.GetChunkX() * cChunkDef::Width) || + (m_StartX >= a_ChunkDesc.GetChunkX() * cChunkDef::Width + cChunkDef::Width) || + (m_EndZ <= a_ChunkDesc.GetChunkZ() * cChunkDef::Width) || + (m_StartZ >= a_ChunkDesc.GetChunkZ() * cChunkDef::Width + cChunkDef::Width) + ) + { + // The chunk is not intersecting the room at all, bail out + return; + } + int b = m_FloorHeight + 1; // Bottom + int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top + ReplaceCuboid(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE); // Floor + ReplaceCuboid(a_ChunkDesc, m_StartX + 1, b, m_StartZ + 1, m_EndX, t, m_EndZ, E_BLOCK_AIR); // Insides + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_StartX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XM wall + ReplaceCuboid(a_ChunkDesc, m_EndX, b, m_StartZ, m_EndX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XP wall + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_EndX + 1, t, m_StartZ + 1, E_BLOCK_COBBLESTONE); // ZM wall + ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_EndZ, m_EndX + 1, t, m_EndZ + 1, E_BLOCK_COBBLESTONE); // ZP wall + TryPlaceChest(a_ChunkDesc, m_Chest1); + TryPlaceChest(a_ChunkDesc, m_Chest2); + } +} ; + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cDungeonRoomsFinisher: + +cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize) : + super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024), + m_HeightGen(a_HeightGen), + m_MaxHalfSize((a_MaxSize + 1) / 2), + m_MinHalfSize((a_MinSize + 1) / 2) +{ + // Normalize the min and max size: + if (m_MinHalfSize > m_MaxHalfSize) + { + std::swap(m_MinHalfSize, m_MaxHalfSize); + } +} + + + + + + +cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) +{ + // Select a random room size in each direction: + int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7; + int HalfSizeX = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1)); + rnd = rnd / 32; + int HalfSizeZ = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1)); + rnd = rnd / 32; + + // Select a random floor height for the room, based on the height generator: + int ChunkX, ChunkZ; + int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ; + cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ); + cChunkDef::HeightMap HeightMap; + m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap); + int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ} + Height = 10 + (rnd % std::max(1, (Height - 14))); + + // Create the dungeon room descriptor: + return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise)); +} + + + + diff --git a/src/Generating/DungeonRoomsFinisher.h b/src/Generating/DungeonRoomsFinisher.h new file mode 100644 index 000000000..542a39682 --- /dev/null +++ b/src/Generating/DungeonRoomsFinisher.h @@ -0,0 +1,47 @@ + +// DungeonRoomsFinisher.h + +// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms + + + + + +#pragma once + +#include "GridStructGen.h" + + + + + +class cDungeonRoomsFinisher : + public cGridStructGen +{ + typedef cGridStructGen super; + +public: + /** Creates a new dungeon room finisher. + a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain. + a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across. */ + cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize); + +protected: + + /** The height gen that is used for limiting the rooms' Y coords */ + cTerrainHeightGen & m_HeightGen; + + /** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */ + int m_MaxHalfSize; + + /** Minimum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 2 (vanilla). */ + int m_MinHalfSize; + + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override; +} ; + + + + From 7146ed3065796e3f719745d7169b77340f26dc37 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 16:36:01 +0300 Subject: [PATCH 069/102] VS Profiling: Shutdown the profiler on error. --- MCServer/profile_run.cmd | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MCServer/profile_run.cmd b/MCServer/profile_run.cmd index 58efea64a..1ed47ac11 100644 --- a/MCServer/profile_run.cmd +++ b/MCServer/profile_run.cmd @@ -45,7 +45,7 @@ if %outputdir%n == n ( -::Create the output directory, if it didn't exist +:: Create the output directory, if it didn't exist mkdir %outputdir% @@ -60,7 +60,7 @@ if errorlevel 1 goto haderror :: Launch the application via the profiler %pt%\vsperfcmd /launch:%app% -if errorlevel 1 goto haderror +if errorlevel 1 goto haderrorshutdown :: Shut down the profiler (this command waits, until the application is terminated) %pt%\vsperfcmd /shutdown @@ -86,6 +86,10 @@ goto finished +:haderrorshutdown +echo An error was encountered, shutting down the profiler +%pt%\vsperfcmd /shutdown + :haderror echo An error was encountered pause From 3a60f2cd83ea265a0a59eec12b24fae11a36e998 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 16:55:43 +0300 Subject: [PATCH 070/102] Profiling: Added profiling script for x64 executable. --- MCServer/profile_run.cmd | 11 ++++++----- MCServer/profile_run_debug.cmd | 2 +- MCServer/profile_run_x64.cmd | 5 +++++ 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 MCServer/profile_run_x64.cmd diff --git a/MCServer/profile_run.cmd b/MCServer/profile_run.cmd index 1ed47ac11..6137e9d4d 100644 --- a/MCServer/profile_run.cmd +++ b/MCServer/profile_run.cmd @@ -12,7 +12,8 @@ :: It expects the MS Performance tools installed in C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools :: You can override this path by setting the pt environment variable prior to launching this script :: -:: By default it will launch the release version of MCServer; set the app environment variable to another executable to run that instead. +:: By default it will launch the 32-bit release version of MCServer; set the app environment variable to another executable to run that instead. +:: Set the IsExecutablex64 env variable to \x64 to profile a 64-bit executable instead (available as the profile_run_x64.cmd script) :: Note that the app needs to be compiled with the "/PROFILE" flag in order for the profiling to work @@ -55,15 +56,15 @@ mkdir %outputdir% :: Start the profiler set outputname=profile.vsp set output=%outputdir%\%outputname% -%pt%\vsperfcmd /start:sample /output:%output% +%pt%%IsExecutablex64%\vsperfcmd /start:sample /output:%output% if errorlevel 1 goto haderror :: Launch the application via the profiler -%pt%\vsperfcmd /launch:%app% +%pt%%IsExecutablex64%\vsperfcmd /launch:%app% if errorlevel 1 goto haderrorshutdown :: Shut down the profiler (this command waits, until the application is terminated) -%pt%\vsperfcmd /shutdown +%pt%%IsExecutablex64%\vsperfcmd /shutdown if errorlevel 1 goto haderror @@ -88,7 +89,7 @@ goto finished :haderrorshutdown echo An error was encountered, shutting down the profiler -%pt%\vsperfcmd /shutdown +%pt%%IsExecutablex64%\vsperfcmd /shutdown :haderror echo An error was encountered diff --git a/MCServer/profile_run_debug.cmd b/MCServer/profile_run_debug.cmd index 8bf85f049..a9792541a 100644 --- a/MCServer/profile_run_debug.cmd +++ b/MCServer/profile_run_debug.cmd @@ -2,4 +2,4 @@ :: This script uses the profile_run.cmd script to run profiling on the DebugProfile executable set app=MCServer_debug_profile.exe -call profile_run.cmd \ No newline at end of file +call profile_run.cmd diff --git a/MCServer/profile_run_x64.cmd b/MCServer/profile_run_x64.cmd new file mode 100644 index 000000000..242136f4b --- /dev/null +++ b/MCServer/profile_run_x64.cmd @@ -0,0 +1,5 @@ +@echo off +:: This script uses the profile_run.cmd script to run profiling on a x64 release executable + +set IsExecutablex64=\x64 +call profile_run.cmd From 2d569ce6ddae1e4d133ed79feeaefa53b5d6999b Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 17:13:46 +0300 Subject: [PATCH 071/102] DungeonRooms: Replaced explicit switch with CanBeTerraformed(). --- src/Generating/DungeonRoomsFinisher.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 37409d486..c662ca6b4 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -114,18 +114,10 @@ protected: { for (int x = RelStartX; x < RelEndX; x++) { - switch (a_ChunkDesc.GetBlockType(x, y, z)) + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) { - case E_BLOCK_STONE: - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_GRAVEL: - case E_BLOCK_SAND: - { - a_ChunkDesc.SetBlockType(x, y, z, a_DstBlockType); - break; - } - } // switch (GetBlockType) + a_ChunkDesc.SetBlockType(x, y, z, a_DstBlockType); + } } // for x } // for z } // for z From a40f3580641488c0dc2df65154e47a1b79b26470 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 17:25:38 +0300 Subject: [PATCH 072/102] DungeonRooms: Random pattern for floors. --- src/Generating/DungeonRoomsFinisher.cpp | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index c662ca6b4..4dbbb0a11 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "DungeonRoomsFinisher.h" +#include "../FastRandom.h" @@ -125,6 +126,35 @@ protected: + /** Fills the specified area of blocks in the chunk with a random pattern of the specified blocktypes, if they are one of the overwritten block types. + The coords are absolute, start coords are inclusive, end coords are exclusive. The first blocktype uses 75% chance, the second 25% chance. */ + void ReplaceCuboidRandom(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType1, BLOCKTYPE a_DstBlockType2) + { + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1); + int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1); + int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width); + int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width); + cFastRandom rnd; + for (int y = a_StartY; y < a_EndY; y++) + { + for (int z = RelStartZ; z < RelEndZ; z++) + { + for (int x = RelStartX; x < RelEndX; x++) + { + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) + { + BLOCKTYPE BlockType = (rnd.NextInt(101) < 75) ? a_DstBlockType1 : a_DstBlockType2; + a_ChunkDesc.SetBlockType(x, y, z, BlockType); + } + } // for x + } // for z + } // for z + } + + + /** Tries to place a chest at the specified (absolute) coords. Does nothing if the coords are outside the chunk. */ void TryPlaceChest(cChunkDesc & a_ChunkDesc, const Vector3i & a_Chest) @@ -160,8 +190,9 @@ protected: } int b = m_FloorHeight + 1; // Bottom int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top - ReplaceCuboid(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE); // Floor + ReplaceCuboidRandom(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE, E_BLOCK_COBBLESTONE); // Floor ReplaceCuboid(a_ChunkDesc, m_StartX + 1, b, m_StartZ + 1, m_EndX, t, m_EndZ, E_BLOCK_AIR); // Insides + // Walls: ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_StartX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XM wall ReplaceCuboid(a_ChunkDesc, m_EndX, b, m_StartZ, m_EndX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XP wall ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_EndX + 1, t, m_StartZ + 1, E_BLOCK_COBBLESTONE); // ZM wall From 0c3c136c72da69c0d100b40689fa931c197fb522 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 26 Aug 2014 17:46:14 +0300 Subject: [PATCH 073/102] DungeonRooms: Chests are never placed next to each other. --- src/Generating/DungeonRoomsFinisher.cpp | 49 ++++++++++++++----------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 4dbbb0a11..f4fb9b222 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -40,10 +40,22 @@ public: m_EndX(a_OriginX + a_HalfSizeX), m_StartZ(a_OriginZ - a_HalfSizeZ), m_EndZ(a_OriginZ + a_HalfSizeZ), - m_FloorHeight(a_FloorHeight), - m_Chest1(SelectChestCoords(a_Noise, a_OriginX + 1, a_OriginZ)), - m_Chest2(SelectChestCoords(a_Noise, a_OriginX + 2, a_OriginZ)) + m_FloorHeight(a_FloorHeight) { + /* + Pick coords next to the wall for the chests. + This is done by indexing the possible coords, picking any one for the first chest + and then picking another position for the second chest that is not adjacent to the first pos + */ + int rnd = a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7; + int SizeX = m_EndX - m_StartX - 1; + int SizeZ = m_EndZ - m_StartZ - 1; + int NumPositions = 2 * SizeX + 2 * SizeZ; + int FirstChestPos = rnd % NumPositions; // The corner positions are a bit more likely, but we don't mind + rnd = rnd / 512; + int SecondChestPos = (FirstChestPos + 2 + (rnd % (NumPositions - 3))) % NumPositions; + m_Chest1 = DecodeChestCoords(FirstChestPos, SizeX, SizeZ); + m_Chest2 = DecodeChestCoords(SecondChestPos, SizeX, SizeZ); } protected: @@ -65,36 +77,29 @@ protected: - /** Selects the coords for the chest, using the noise and coords provided. - Assumes that the room XZ ranges are already assigned. */ - Vector3i SelectChestCoords(cNoise & a_Noise, int a_X, int a_Z) + /** Decodes the position index along the room walls into a proper 2D position for a chest. */ + Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ) { - // Pick a coord next to the wall: - int rnd = a_Noise.IntNoise2DInt(a_X, a_Z) / 7; - int SizeX = m_EndX - m_StartX - 1; - int SizeZ = m_EndZ - m_StartZ - 1; - rnd = rnd % (2 * SizeX + 2 * SizeZ); - - if (rnd < SizeX) + if (a_PosIdx < a_SizeX) { // Return a coord on the ZM side of the room: - return Vector3i(m_StartX + rnd + 1, E_META_CHEST_FACING_ZP, m_StartZ + 1); + return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZP, m_StartZ + 1); } - rnd -= SizeX; - if (rnd < SizeZ) + a_PosIdx -= a_SizeX; + if (a_PosIdx < a_SizeZ) { // Return a coord on the XP side of the room: - return Vector3i(m_EndX - 1, E_META_CHEST_FACING_XM, m_StartZ + rnd + 1); + return Vector3i(m_EndX - 1, E_META_CHEST_FACING_XM, m_StartZ + a_PosIdx + 1); } - rnd -= SizeZ; - if (rnd < SizeX) + a_PosIdx -= a_SizeZ; + if (a_PosIdx < a_SizeX) { // Return a coord on the ZP side of the room: - return Vector3i(m_StartX + rnd + 1, E_META_CHEST_FACING_ZM, m_StartZ + 1); + return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZM, m_StartZ + 1); } - rnd -= SizeX; + a_PosIdx -= a_SizeX; // Return a coord on the XM side of the room: - return Vector3i(m_StartX + 1, E_META_CHEST_FACING_XP, m_StartZ + rnd + 1); + return Vector3i(m_StartX + 1, E_META_CHEST_FACING_XP, m_StartZ + a_PosIdx + 1); } From c6beb9760bcfb86ac03317dbb252e0478107d009 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 08:12:26 +0300 Subject: [PATCH 074/102] DungeonRooms: Added the spawner in the center of the room. --- src/Generating/DungeonRoomsFinisher.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index f4fb9b222..9555ee86c 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -197,13 +197,28 @@ protected: int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top ReplaceCuboidRandom(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE, E_BLOCK_COBBLESTONE); // Floor ReplaceCuboid(a_ChunkDesc, m_StartX + 1, b, m_StartZ + 1, m_EndX, t, m_EndZ, E_BLOCK_AIR); // Insides + // Walls: ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_StartX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XM wall ReplaceCuboid(a_ChunkDesc, m_EndX, b, m_StartZ, m_EndX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XP wall ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_EndX + 1, t, m_StartZ + 1, E_BLOCK_COBBLESTONE); // ZM wall ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_EndZ, m_EndX + 1, t, m_EndZ + 1, E_BLOCK_COBBLESTONE); // ZP wall + + // Place chests: TryPlaceChest(a_ChunkDesc, m_Chest1); TryPlaceChest(a_ChunkDesc, m_Chest2); + + // Place the spawner: + int CenterX = (m_StartX + m_EndX) / 2 - a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int CenterZ = (m_StartZ + m_EndZ) / 2 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + if ( + (CenterX >= 0) && (CenterX < cChunkDef::Width) && + (CenterZ >= 0) && (CenterZ < cChunkDef::Width) + ) + { + a_ChunkDesc.SetBlockTypeMeta(CenterX, b, CenterZ, E_BLOCK_MOB_SPAWNER, 0); + // TODO: Set the spawned mob + } } } ; From 24a092d9cb5013d55a85b5df022e4e905141e069 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 27 Aug 2014 09:05:43 +0200 Subject: [PATCH 075/102] AnvilStats: Rewritten to use CMake. --- Tools/AnvilStats/.gitignore | 4 + Tools/AnvilStats/AnvilStats.sln | 55 ---- Tools/AnvilStats/AnvilStats.vcproj | 468 ----------------------------- Tools/AnvilStats/CMakeLists.txt | 122 ++++++++ 4 files changed, 126 insertions(+), 523 deletions(-) delete mode 100644 Tools/AnvilStats/AnvilStats.sln delete mode 100644 Tools/AnvilStats/AnvilStats.vcproj create mode 100644 Tools/AnvilStats/CMakeLists.txt diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore index 96210cfc9..afd34cdda 100644 --- a/Tools/AnvilStats/.gitignore +++ b/Tools/AnvilStats/.gitignore @@ -1,3 +1,7 @@ +*.vcproj +*.vcxproj +*.sln +*.user .xls Statistics.txt *.bmp diff --git a/Tools/AnvilStats/AnvilStats.sln b/Tools/AnvilStats/AnvilStats.sln deleted file mode 100644 index 46bed8969..000000000 --- a/Tools/AnvilStats/AnvilStats.sln +++ /dev/null @@ -1,55 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2013 for Windows Desktop -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnvilStats", "AnvilStats.vcxproj", "{CF996A5E-0A86-4004-9710-682B06B5AEBA}" - ProjectSection(ProjectDependencies) = postProject - {B61007AC-B557-4B67-A765-E468C0C3A821} = {B61007AC-B557-4B67-A765-E468C0C3A821} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\lib\zlib\zlib.vcxproj", "{B61007AC-B557-4B67-A765-E468C0C3A821}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - DebugProfile|Win32 = DebugProfile|Win32 - MinSizeRel|Win32 = MinSizeRel|Win32 - Release profiled|Win32 = Release profiled|Win32 - Release|Win32 = Release|Win32 - ReleaseProfile|Win32 = ReleaseProfile|Win32 - RelWithDebInfo|Win32 = RelWithDebInfo|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Debug|Win32.ActiveCfg = Debug|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Debug|Win32.Build.0 = Debug|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.DebugProfile|Win32.ActiveCfg = Debug|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.DebugProfile|Win32.Build.0 = Debug|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.MinSizeRel|Win32.ActiveCfg = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.MinSizeRel|Win32.Build.0 = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release profiled|Win32.ActiveCfg = Release profiled|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release profiled|Win32.Build.0 = Release profiled|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release|Win32.ActiveCfg = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release|Win32.Build.0 = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.ReleaseProfile|Win32.ActiveCfg = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.ReleaseProfile|Win32.Build.0 = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.RelWithDebInfo|Win32.ActiveCfg = Release|Win32 - {CF996A5E-0A86-4004-9710-682B06B5AEBA}.RelWithDebInfo|Win32.Build.0 = Release|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Debug|Win32.ActiveCfg = Debug|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Debug|Win32.Build.0 = Debug|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.DebugProfile|Win32.ActiveCfg = DebugProfile|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.DebugProfile|Win32.Build.0 = DebugProfile|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Release profiled|Win32.ActiveCfg = Release|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Release profiled|Win32.Build.0 = Release|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Release|Win32.ActiveCfg = Release|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.Release|Win32.Build.0 = Release|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.ReleaseProfile|Win32.ActiveCfg = ReleaseProfile|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.ReleaseProfile|Win32.Build.0 = ReleaseProfile|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32 - {B61007AC-B557-4B67-A765-E468C0C3A821}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Tools/AnvilStats/AnvilStats.vcproj b/Tools/AnvilStats/AnvilStats.vcproj deleted file mode 100644 index c7a2e9390..000000000 --- a/Tools/AnvilStats/AnvilStats.vcproj +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/AnvilStats/CMakeLists.txt b/Tools/AnvilStats/CMakeLists.txt new file mode 100644 index 000000000..8cbcf6be4 --- /dev/null +++ b/Tools/AnvilStats/CMakeLists.txt @@ -0,0 +1,122 @@ + +cmake_minimum_required (VERSION 2.8.3) + +project (AnvilStats) + +include(../../SetFlags.cmake) + +set_flags() +set_lib_flags() + + +# Set include paths to the used libraries: +include_directories("../../lib") +include_directories("../../src") + + + +function(flatten_files arg1) + set(res "") + foreach(f ${${arg1}}) + get_filename_component(f ${f} ABSOLUTE) + list(APPEND res ${f}) + endforeach() + set(${arg1} "${res}" PARENT_SCOPE) +endfunction() + +add_subdirectory(../../lib/zlib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/lib/zlib) + +set_exe_flags() + +# Include the shared files: +set(SHARED_SRC + ../../src/ByteBuffer.cpp + ../../src/StringUtils.cpp + ../../src/LoggerListeners.cpp + ../../src/Logger.cpp + ../../src/WorldStorage/FastNBT.cpp + ../BiomeVisualiser/BiomeColors.cpp +) + +set(SHARED_HDR + ../../src/ByteBuffer.h + ../../src/StringUtils.h + ../../src/LoggerListeners.h + ../../src/Logger.h + ../../src/WorldStorage/FastNBT.h + ../BiomeVisualiser/BiomeColors.h +) + +set(SHARED_OSS_SRC + ../../src/OSSupport/CriticalSection.cpp + ../../src/OSSupport/Event.cpp + ../../src/OSSupport/File.cpp + ../../src/OSSupport/GZipFile.cpp + ../../src/OSSupport/IsThread.cpp + ../../src/OSSupport/Timer.cpp +) + +set(SHARED_OSS_HDR + ../../src/OSSupport/CriticalSection.h + ../../src/OSSupport/Event.h + ../../src/OSSupport/File.h + ../../src/OSSupport/GZipFile.h + ../../src/OSSupport/IsThread.h + ../../src/OSSupport/Timer.h +) + +flatten_files(SHARED_SRC) +flatten_files(SHARED_HDR) +flatten_files(SHARED_OSS_SRC) +flatten_files(SHARED_OSS_HDR) +source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR}) +source_group("Shared\\OSSupport" FILES ${SHARED_OSS_SRC} ${SHARED_OSS_HDR}) + + + +# Include the main source files: +set(SOURCES + AnvilStats.cpp + BiomeMap.cpp + ChunkExtract.cpp + Globals.cpp + HeightBiomeMap.cpp + HeightMap.cpp + ImageComposingCallback.cpp + Processor.cpp + SpringStats.cpp + Statistics.cpp + Utils.cpp +) + +set(HEADERS + BiomeMap.h + Callback.h + ChunkExtract.h + Globals.h + HeightBiomeMap.h + HeightMap.h + ImageComposingCallback.h + Processor.h + SpringStats.h + Statistics.h + Utils.h + + AnvilStats.txt +) + +source_group("" FILES ${SOURCES} ${HEADERS}) + +add_definitions(-DNBT_RESERVE_SIZE=10000) + +add_executable(AnvilStats + ${SOURCES} + ${HEADERS} + ${SHARED_SRC} + ${SHARED_HDR} + ${SHARED_OSS_SRC} + ${SHARED_OSS_HDR} +) + +target_link_libraries(AnvilStats zlib) + From d783753cb5050e3a16363cd8a2bfb4b361c130c0 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 27 Aug 2014 09:46:59 +0200 Subject: [PATCH 076/102] AnvilStats: initial per-height blocktype implementation (WIP). --- Tools/AnvilStats/Globals.h | 11 +++++ Tools/AnvilStats/Statistics.cpp | 87 +++++++++++++++++++++++++++++++-- Tools/AnvilStats/Statistics.h | 3 ++ 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/Tools/AnvilStats/Globals.h b/Tools/AnvilStats/Globals.h index df1430cc4..21d54739a 100644 --- a/Tools/AnvilStats/Globals.h +++ b/Tools/AnvilStats/Globals.h @@ -241,6 +241,17 @@ public: +/** Clamp value to the specified range. */ +template +T Clamp(T a_Value, T a_Min, T a_Max) +{ + return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value); +} + + + + + // Common headers (part 2, with macros): #include "../../src/ChunkDef.h" #include "../../src/BlockID.h" diff --git a/Tools/AnvilStats/Statistics.cpp b/Tools/AnvilStats/Statistics.cpp index f7519fd37..11b9f09c5 100644 --- a/Tools/AnvilStats/Statistics.cpp +++ b/Tools/AnvilStats/Statistics.cpp @@ -26,9 +26,11 @@ cStatistics::cStats::cStats(void) : m_MinChunkZ(0x7fffffff), m_MaxChunkZ(0x80000000) { - memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts)); - memset(m_BlockCounts, 0, sizeof(m_BlockCounts)); - memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity)); + memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts)); + memset(m_BlockCounts, 0, sizeof(m_BlockCounts)); + memset(m_PerHeightBlockCounts, 0, sizeof(m_PerHeightBlockCounts)); + memset(m_PerHeightSpawners, 0, sizeof(m_PerHeightSpawners)); + memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity)); } @@ -46,6 +48,11 @@ void cStatistics::cStats::Add(const cStatistics::cStats & a_Stats) for (int j = 0; j <= 255; j++) { m_BlockCounts[i][j] += a_Stats.m_BlockCounts[i][j]; + m_PerHeightBlockCounts[i][j] += a_Stats.m_PerHeightBlockCounts[i][j]; + } + for (int j = 0; j < ARRAYCOUNT(m_PerHeightSpawners[0]); j++) + { + m_PerHeightSpawners[i][j] += a_Stats.m_PerHeightSpawners[i][j]; } } for (int i = 0; i < ARRAYCOUNT(m_SpawnerEntity); i++) @@ -149,6 +156,7 @@ bool cStatistics::OnSection for (int y = 0; y < 16; y++) { + int Height = (int)a_Y * 16 + y; for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) @@ -156,6 +164,7 @@ bool cStatistics::OnSection unsigned char Biome = m_BiomeData[x + 16 * z]; // Cannot use cChunkDef, different datatype unsigned char BlockType = cChunkDef::GetBlock(a_BlockTypes, x, y, z); m_Stats.m_BlockCounts[Biome][BlockType] += 1; + m_Stats.m_PerHeightBlockCounts[Height][BlockType] += 1; } } } @@ -259,16 +268,27 @@ bool cStatistics::OnTileTick( void cStatistics::OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag) { + // Get the spawned entity type: int EntityIDTag = a_NBT.FindChildByName(a_TileEntityTag, "EntityId"); if ((EntityIDTag < 0) || (a_NBT.GetType(EntityIDTag) != TAG_String)) { return; } eEntityType Ent = GetEntityType(a_NBT.GetString(EntityIDTag)); - if (Ent < ARRAYCOUNT(m_Stats.m_SpawnerEntity)) + if (Ent >= ARRAYCOUNT(m_Stats.m_SpawnerEntity)) { - m_Stats.m_SpawnerEntity[Ent] += 1; + return; } + m_Stats.m_SpawnerEntity[Ent] += 1; + + // Get the spawner pos: + int PosYTag = a_NBT.FindChildByName(a_TileEntityTag, "y"); + if ((PosYTag < 0) || (a_NBT.GetType(PosYTag) != TAG_Int)) + { + return; + } + int BlockY = Clamp(a_NBT.GetInt(PosYTag), 0, 255); + m_Stats.m_PerHeightSpawners[BlockY][Ent] += 1; } @@ -316,6 +336,8 @@ cStatisticsFactory::~cStatisticsFactory() SaveBiomes(); LOG(" BlockTypes.xls"); SaveBlockTypes(); + LOG(" PerHeightBlockTypes.xls"); + SavePerHeightBlockTypes(); LOG(" BiomeBlockTypes.xls"); SaveBiomeBlockTypes(); LOG(" Spawners.xls"); @@ -395,6 +417,61 @@ void cStatisticsFactory::SaveBlockTypes(void) +void cStatisticsFactory::SavePerHeightBlockTypes(void) +{ + // Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns + + cFile f; + if (!f.Open("PerHeightBlockTypes.xls", cFile::fmWrite)) + { + LOG("Cannot write to file PerHeightBlockTypes.xls. Statistics not written."); + return; + } + + // Write header: + f.Printf("Blocks 0 - 127:\nHeight\t"); + for (int i = 0; i < 128; i++) + { + f.Printf("\t%s(%d)", GetBlockTypeString(i), i); + } + f.Printf("\n"); + + // Write first half: + for (int y = 0; y < 256; y++) + { + f.Printf("%d", y); + for (int BlockType = 0; BlockType < 128; BlockType++) + { + f.Printf("\t%d", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); + } // for BlockType + f.Printf("\n"); + } // for y - height (0 - 127) + f.Printf("\n"); + + // Write second header: + f.Printf("Blocks 128 - 255:\nHeight\t"); + for (int i = 128; i < 256; i++) + { + f.Printf("\t%s(%d)", GetBlockTypeString(i), i); + } + f.Printf("\n"); + + // Write second half: + for (int y = 0; y < 256; y++) + { + f.Printf("%d", y); + for (int BlockType = 128; BlockType < 256; BlockType++) + { + f.Printf("\t%d", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); + } // for BlockType + f.Printf("\n"); + } // for y - height (0 - 127) +} + + + + + void cStatisticsFactory::SaveBiomeBlockTypes(void) { // Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns diff --git a/Tools/AnvilStats/Statistics.h b/Tools/AnvilStats/Statistics.h index 53e353f22..f6165edd9 100644 --- a/Tools/AnvilStats/Statistics.h +++ b/Tools/AnvilStats/Statistics.h @@ -31,6 +31,8 @@ public: UInt64 m_NumEntities; UInt64 m_NumTileEntities; UInt64 m_NumTileTicks; + UInt64 m_PerHeightBlockCounts[256][256]; // First dimension is the height, second dimension is BlockType + UInt64 m_PerHeightSpawners[256][entMax + 1]; // First dimension is the height, second dimension is spawned entity type int m_MinChunkX, m_MaxChunkX; // X coords range int m_MinChunkZ, m_MaxChunkZ; // Z coords range @@ -128,6 +130,7 @@ protected: void JoinResults(void); void SaveBiomes(void); void SaveBlockTypes(void); + void SavePerHeightBlockTypes(void); void SaveBiomeBlockTypes(void); void SaveStatistics(void); void SaveSpawners(void); From ccaa51f9132a1427a82e24a5d6eaf5d1992f7df9 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 11:52:54 +0300 Subject: [PATCH 077/102] AnvilStats: Fixed Win64 compilation. --- Tools/AnvilStats/Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/AnvilStats/Utils.cpp b/Tools/AnvilStats/Utils.cpp index baa87bd69..d7543cb4c 100644 --- a/Tools/AnvilStats/Utils.cpp +++ b/Tools/AnvilStats/Utils.cpp @@ -272,7 +272,7 @@ extern const char * GetEntityTypeString(eEntityType a_EntityType) int GetNumCores(void) { // Get number of cores by querying the system process affinity mask (Windows-specific) - DWORD Affinity, ProcAffinity; + DWORD_PTR Affinity, ProcAffinity; GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity); int NumCores = 0; while (Affinity > 0) From b361e994ef4aac5e2f5672a291d4abf1a3714bc6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 11:53:46 +0300 Subject: [PATCH 078/102] AnvilStats: Added cmake directive for larger executable stack. This fixes runtime "stack overflow" errors caused by large stack-allocated arrays used for decompression. --- Tools/AnvilStats/CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Tools/AnvilStats/CMakeLists.txt b/Tools/AnvilStats/CMakeLists.txt index 8cbcf6be4..557a4c17a 100644 --- a/Tools/AnvilStats/CMakeLists.txt +++ b/Tools/AnvilStats/CMakeLists.txt @@ -118,5 +118,27 @@ add_executable(AnvilStats ${SHARED_OSS_HDR} ) + target_link_libraries(AnvilStats zlib) + + + + +# Under MSVC we need to enlarge the default stack size for the executable: +if (MSVC) + get_target_property(TEMP AnvilStats LINK_FLAGS) + if (TEMP STREQUAL "TEMP-NOTFOUND") + SET(TEMP "") # set to empty string + message("LINKER_FLAGS not found") + else () + SET(TEMP "${TEMP} ") # a space to cleanly separate from existing content + message("LINKER_FLAGS: ${LINKER_FLAGS}") + endif () + # append our values + SET(TEMP "${TEMP}/STACK:16777216") + set_target_properties(AnvilStats PROPERTIES LINK_FLAGS ${TEMP}) +endif () + + + From 751d345c59bbaf265393c5306f181ee3654a35a6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 11:54:22 +0300 Subject: [PATCH 079/102] AnvilStats: Ignoring output XLS files. --- Tools/AnvilStats/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore index afd34cdda..f093bbe7d 100644 --- a/Tools/AnvilStats/.gitignore +++ b/Tools/AnvilStats/.gitignore @@ -11,3 +11,4 @@ Profiling *.png world/ *.html +*.xls From af47b5ece2bfe274e305f0602dff8e7a74ae0360 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 12:24:56 +0300 Subject: [PATCH 080/102] AnvilStats: Added per-height spawner stats. --- Tools/AnvilStats/Statistics.cpp | 48 ++++++++++++++++++++++++++++++--- Tools/AnvilStats/Statistics.h | 3 +++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Tools/AnvilStats/Statistics.cpp b/Tools/AnvilStats/Statistics.cpp index 11b9f09c5..c8a98b488 100644 --- a/Tools/AnvilStats/Statistics.cpp +++ b/Tools/AnvilStats/Statistics.cpp @@ -342,6 +342,8 @@ cStatisticsFactory::~cStatisticsFactory() SaveBiomeBlockTypes(); LOG(" Spawners.xls"); SaveSpawners(); + LOG(" PerHeightSpawners.xls"); + SavePerHeightSpawners(); } @@ -429,7 +431,7 @@ void cStatisticsFactory::SavePerHeightBlockTypes(void) } // Write header: - f.Printf("Blocks 0 - 127:\nHeight\t"); + f.Printf("Blocks 0 - 127:\nHeight"); for (int i = 0; i < 128; i++) { f.Printf("\t%s(%d)", GetBlockTypeString(i), i); @@ -442,14 +444,14 @@ void cStatisticsFactory::SavePerHeightBlockTypes(void) f.Printf("%d", y); for (int BlockType = 0; BlockType < 128; BlockType++) { - f.Printf("\t%d", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); + f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); } // for BlockType f.Printf("\n"); } // for y - height (0 - 127) f.Printf("\n"); // Write second header: - f.Printf("Blocks 128 - 255:\nHeight\t"); + f.Printf("Blocks 128 - 255:\nHeight"); for (int i = 128; i < 256; i++) { f.Printf("\t%s(%d)", GetBlockTypeString(i), i); @@ -462,7 +464,7 @@ void cStatisticsFactory::SavePerHeightBlockTypes(void) f.Printf("%d", y); for (int BlockType = 128; BlockType < 256; BlockType++) { - f.Printf("\t%d", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); + f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]); } // for BlockType f.Printf("\n"); } // for y - height (0 - 127) @@ -598,3 +600,41 @@ void cStatisticsFactory::SaveSpawners(void) + +void cStatisticsFactory::SavePerHeightSpawners(void) +{ + cFile f; + if (!f.Open("PerHeightSpawners.xls", cFile::fmWrite)) + { + LOG("Cannot write to file PerHeightSpawners.xls. Statistics not written."); + return; + } + + // Write header: + f.Printf("Height\tTotal"); + for (int i = 0; i < entMax; i++) + { + f.Printf("\t%s", GetEntityTypeString((eEntityType)i)); + } + f.Printf("\n"); + + // Write individual lines: + for (int y = 0; y < 256; y++) + { + UInt64 Total = 0; + for (int i = 0; i < entMax; i++) + { + Total += m_CombinedStats.m_PerHeightSpawners[y][i]; + } + f.Printf("%d\t%llu", y, Total); + for (int i = 0; i < entMax; i++) + { + f.Printf("\t%llu", m_CombinedStats.m_PerHeightSpawners[y][i]); + } + f.Printf("\n"); + } +} + + + + diff --git a/Tools/AnvilStats/Statistics.h b/Tools/AnvilStats/Statistics.h index f6165edd9..1b012e283 100644 --- a/Tools/AnvilStats/Statistics.h +++ b/Tools/AnvilStats/Statistics.h @@ -76,6 +76,8 @@ protected: virtual bool OnEmptySection(unsigned char a_Y) override; + virtual bool OnSectionsFinished(void) override { return false; } // continue processing + virtual bool OnEntity( const AString & a_EntityType, double a_PosX, double a_PosY, double a_PosZ, @@ -134,6 +136,7 @@ protected: void SaveBiomeBlockTypes(void); void SaveStatistics(void); void SaveSpawners(void); + void SavePerHeightSpawners(void); } ; From cde195c1569f22027306adf12e0e3e520d69b9f8 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 12:29:57 +0300 Subject: [PATCH 081/102] AnvilStats: Fixed thread start race condition. The whole program would sometimes fail to process anything because the threads were waited-for before they were started. --- Tools/AnvilStats/Processor.cpp | 24 ++++++++++++++++-------- Tools/AnvilStats/Processor.h | 10 ++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Tools/AnvilStats/Processor.cpp b/Tools/AnvilStats/Processor.cpp index a16f78c18..6c4bb0ad5 100644 --- a/Tools/AnvilStats/Processor.cpp +++ b/Tools/AnvilStats/Processor.cpp @@ -28,6 +28,7 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces m_Callback(a_Callback), m_ParentProcessor(a_ParentProcessor) { + LOG("Created a new thread: %p", this); super::Start(); } @@ -35,11 +36,20 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces +void cProcessor::cThread::WaitForStart(void) +{ + m_HasStarted.Wait(); +} + + + + + void cProcessor::cThread::Execute(void) { - LOG("Started a new thread: %d", cIsThread::GetCurrentID()); + LOG("Started a new thread: %p, ID %d", this, cIsThread::GetCurrentID()); - m_ParentProcessor.m_ThreadsHaveStarted.Set(); + m_HasStarted.Set(); for (;;) { @@ -52,7 +62,7 @@ void cProcessor::cThread::Execute(void) ProcessFile(FileName); } // for-ever - LOG("Thread %d terminated", cIsThread::GetCurrentID()); + LOG("Thread %p (ID %d) terminated", this, cIsThread::GetCurrentID()); } @@ -522,20 +532,18 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory & #endif // _DEBUG //*/ + // Start all the threads: for (int i = 0; i < NumThreads; i++) { cCallback * Callback = a_CallbackFactory.GetNewCallback(); m_Threads.push_back(new cThread(*Callback, *this)); } - // Wait for the first thread to start processing: - m_ThreadsHaveStarted.Wait(); - - // Wait for all threads to finish - // simply by calling each thread's destructor sequentially + // Wait for all threads to finish: LOG("Waiting for threads to finish"); for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr) { + (*itr)->WaitForStart(); delete *itr; } // for itr - m_Threads[] LOG("Processor finished"); diff --git a/Tools/AnvilStats/Processor.h b/Tools/AnvilStats/Processor.h index 72fea3081..db50ec619 100644 --- a/Tools/AnvilStats/Processor.h +++ b/Tools/AnvilStats/Processor.h @@ -30,6 +30,7 @@ class cProcessor cCallback & m_Callback; cProcessor & m_ParentProcessor; + cEvent m_HasStarted; // cIsThread override: virtual void Execute(void) override; @@ -48,6 +49,9 @@ class cProcessor public: cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor); + + /** Waits until the thread starts processing the callback code. */ + void WaitForStart(void); } ; typedef std::vector cThreads; @@ -65,10 +69,12 @@ protected: AStringList m_FileQueue; cThreads m_Threads; - cEvent m_ThreadsHaveStarted; // This is signalled by each thread to notify the parent thread that it can start waiting for those threads - + + + /** Populates m_FileQueue with Anvil files from the specified folder. */ void PopulateFileQueue(const AString & a_WorldFolder); + /** Returns one filename from m_FileQueue, and removes the name from the queue. */ AString GetOneFileName(void); } ; From 62e1c45ca5352205679a60e963853e8511799657 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 13:25:27 +0300 Subject: [PATCH 082/102] DungeonRooms: Added a height probability distribution function. --- src/Generating/ComposableGenerator.cpp | 9 +++++---- src/Generating/DungeonRoomsFinisher.cpp | 10 +++++++--- src/Generating/DungeonRoomsFinisher.h | 9 +++++++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index a3a9f170d..6f4007d24 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -346,10 +346,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "DungeonRooms") == 0) { - int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48); - int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7); - int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5); - m_FinishGens.push_back(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize)); + int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48); + int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7); + int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5); + AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1"); + m_FinishGens.push_back(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)); } else if (NoCaseCompare(*itr, "Ice") == 0) { diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 9555ee86c..9e039d737 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -230,12 +230,16 @@ protected: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cDungeonRoomsFinisher: -cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize) : +cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) : super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024), m_HeightGen(a_HeightGen), m_MaxHalfSize((a_MaxSize + 1) / 2), - m_MinHalfSize((a_MinSize + 1) / 2) + m_MinHalfSize((a_MinSize + 1) / 2), + m_HeightProbability(cChunkDef::Height) { + // Initialize the height probability distribution: + m_HeightProbability.SetDefString(a_HeightDistrib); + // Normalize the min and max size: if (m_MinHalfSize > m_MaxHalfSize) { @@ -264,7 +268,7 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int cChunkDef::HeightMap HeightMap; m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap); int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ} - Height = 10 + (rnd % std::max(1, (Height - 14))); + Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5); // Create the dungeon room descriptor: return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise)); diff --git a/src/Generating/DungeonRoomsFinisher.h b/src/Generating/DungeonRoomsFinisher.h index 542a39682..2b52c9de6 100644 --- a/src/Generating/DungeonRoomsFinisher.h +++ b/src/Generating/DungeonRoomsFinisher.h @@ -10,6 +10,7 @@ #pragma once #include "GridStructGen.h" +#include "../ProbabDistrib.h" @@ -23,8 +24,9 @@ class cDungeonRoomsFinisher : public: /** Creates a new dungeon room finisher. a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain. - a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across. */ - cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize); + a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across. + a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */ + cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib); protected: @@ -37,6 +39,9 @@ protected: /** Minimum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 2 (vanilla). */ int m_MinHalfSize; + /** The height probability distribution to make the spawners more common in layers 10 - 40, less common outside this range. */ + cProbabDistrib m_HeightProbability; + // cGridStructGen overrides: virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override; From bc44b96059291629b2bc6d1f6c71492fdc1974ed Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 15:12:49 +0300 Subject: [PATCH 083/102] CheckBasicStyle: Relaxed the "space after comma". An apostrophe directly following a comma is not a violation. --- src/CheckBasicStyle.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index bf81a7cd5..08f014e33 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -108,7 +108,7 @@ local g_ViolationPatterns = -- Check that all commas have spaces after them and not in front of them: {" ,", "Extra space before a \",\""}, - {",[^%s\"%%]", "Needs a space after a \",\""}, -- Report all except >> "," << needed for splitting and >>,%s<< needed for formatting + {",[^%s\"%%\']", "Needs a space after a \",\""}, -- Report all except >> "," << needed for splitting and >>,%s<< needed for formatting -- Check that opening braces are not at the end of a code line: {"[^%s].-{\n?$", "Brace should be on a separate line"}, From d8527c5429aa7ecaa31cc78c8c2fd3833d59266d Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 15:13:13 +0300 Subject: [PATCH 084/102] Fixed basic style violations. --- src/LoggerListeners.cpp | 14 +++++++------- src/RankManager.cpp | 10 ++++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 836536cbd..77e2aaf67 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -65,7 +65,7 @@ { case cLogger::llRegular: { - // Gray on black + // Gray on black Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; break; } @@ -93,7 +93,7 @@ virtual void SetDefaultLogColour() override - { + { SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); } @@ -119,13 +119,13 @@ { case cLogger::llRegular: { - // Whatever the console default is + // Whatever the console default is printf("\x1b[0m"); - break; + break; } case cLogger::llInfo: { - // Yellow on black + // Yellow on black printf("\x1b[33;1m"); break; } @@ -133,7 +133,7 @@ { // Red on black printf("\x1b[31;1m"); - break; + break; } case cLogger::llError: { @@ -147,7 +147,7 @@ virtual void SetDefaultLogColour() override { - // Whatever the console default is + // Whatever the console default is printf("\x1b[0m"); } }; diff --git a/src/RankManager.cpp b/src/RankManager.cpp index 65ce33b92..dc6eec9e4 100644 --- a/src/RankManager.cpp +++ b/src/RankManager.cpp @@ -125,7 +125,7 @@ protected: /** Maps lists of groups to rank names. Each group list is either a simple "" if there's only one group, - or ",,...", where the secondary groups are + or ", , ...", where the secondary groups are lowercased and alpha-sorted. This makes the group lists comparable for equivalence, simply by comparing their string names. The ranks are named "" for single-group players, and "AutoMigratedRank_N" for the composite ranks, @@ -507,10 +507,8 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID) // Prepare the DB statement: SQLite::Statement stmt(m_DB, "SELECT PermGroup.Name FROM PermGroup " - "LEFT JOIN RankPermGroup " - "ON PermGroup.PermGroupID = RankPermGroup.PermGroupID " - "LEFT JOIN PlayerRank " - "ON PlayerRank.RankID = RankPermGroup.RankID " + "LEFT JOIN RankPermGroup ON PermGroup.PermGroupID = RankPermGroup.PermGroupID " + "LEFT JOIN PlayerRank ON PlayerRank.RankID = RankPermGroup.RankID " "WHERE PlayerRank.PlayerUUID = ?" ); stmt.bind(1, a_PlayerUUID); @@ -1473,7 +1471,7 @@ void cRankManager::RemovePlayerRank(const AString & a_PlayerUUID) stmt.bind(1, a_PlayerUUID); stmt.exec(); } - catch(const SQLite::Exception & ex) + catch (const SQLite::Exception & ex) { LOGWARNING("%s: Failed to remove rank from player UUID %s: %s", __FUNCTION__, a_PlayerUUID.c_str(), ex.what() From e54a7dc6c4e46c0c657cbd13242253cd1f08102a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 15:21:20 +0300 Subject: [PATCH 085/102] More basic style fixes. --- src/Generating/DungeonRoomsFinisher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 9e039d737..694dcc3cc 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -18,7 +18,7 @@ static const int ROOM_HEIGHT = 4; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cDungeonRoom: class cDungeonRoom : @@ -227,7 +227,7 @@ protected: -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cDungeonRoomsFinisher: cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) : From fe3d8fd8100ed93a35fe5a7f4080cbab1f913490 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 15:41:29 +0300 Subject: [PATCH 086/102] Debuggers: Added a testcase for OnProjectileHitBlock. This is a test for #1326. --- MCServer/Plugins/Debuggers/Debuggers.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 81cf02f3c..179935c08 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -33,6 +33,7 @@ function Initialize(Plugin) PM:AddHook(cPluginManager.HOOK_PROJECTILE_HIT_BLOCK, OnProjectileHitBlock); PM:AddHook(cPluginManager.HOOK_CHUNK_UNLOADING, OnChunkUnloading); PM:AddHook(cPluginManager.HOOK_WORLD_STARTED, OnWorldStarted); + PM:AddHook(cPluginManager.HOOK_PROJECTILE_HIT_BLOCK, OnProjectileHitBlock); -- _X: Disabled so that the normal operation doesn't interfere with anything -- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated); @@ -1545,3 +1546,15 @@ end + +function OnProjectileHitBlock(a_ProjectileEntity, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockHitPos) + -- This simple test is for testing issue #1326 - simply declaring this hook would crash the server upon call + LOG("Projectile hit block") + LOG(" Projectile EntityID: " .. a_ProjectileEntity:GetUniqueID()) + LOG(" Block: {" .. a_BlockX .. ", " .. a_BlockY .. ", " .. a_BlockZ .. "}, face " .. a_BlockFace) + LOG(" HitPos: {" .. a_BlockHitPos.x .. ", " .. a_BlockHitPos.y .. ", " .. a_BlockHitPos.z .. "}") +end + + + + From e54c78923e26e50f8e8839ce352def05a929d9a1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 27 Aug 2014 20:55:28 +0300 Subject: [PATCH 087/102] DungeonRooms: Fixed an off-by-one error. --- src/Generating/DungeonRoomsFinisher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/DungeonRoomsFinisher.cpp b/src/Generating/DungeonRoomsFinisher.cpp index 694dcc3cc..f213455d6 100644 --- a/src/Generating/DungeonRoomsFinisher.cpp +++ b/src/Generating/DungeonRoomsFinisher.cpp @@ -184,9 +184,9 @@ protected: virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override { if ( - (m_EndX <= a_ChunkDesc.GetChunkX() * cChunkDef::Width) || + (m_EndX < a_ChunkDesc.GetChunkX() * cChunkDef::Width) || (m_StartX >= a_ChunkDesc.GetChunkX() * cChunkDef::Width + cChunkDef::Width) || - (m_EndZ <= a_ChunkDesc.GetChunkZ() * cChunkDef::Width) || + (m_EndZ < a_ChunkDesc.GetChunkZ() * cChunkDef::Width) || (m_StartZ >= a_ChunkDesc.GetChunkZ() * cChunkDef::Width + cChunkDef::Width) ) { From 690e6cb6f8d0c67f3725de8398659115ab823f4c Mon Sep 17 00:00:00 2001 From: reiter Date: Thu, 28 Aug 2014 00:01:01 +0200 Subject: [PATCH 088/102] Fixed mob burning. Fixes #1298 --- 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 fe8a7346f..f7ee0b0c0 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1024,7 +1024,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime !IsOnFire() && // Not already burning - GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining + GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining ) { // Burn for 100 ticks, then decide again From e555cb4ab3a783f9dc8980bd5f7e4523bd6711ce Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 00:05:11 +0200 Subject: [PATCH 089/102] Fixed ItemCategory code example. --- MCServer/Plugins/APIDump/APIDesc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index fe56ecee8..3e1a6e3bb 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2570,8 +2570,8 @@ World:ForEachEntity( The following code snippet checks if the player holds a shovel.

 -- a_Player is a {{cPlayer}} object, possibly received as a hook param
-local HeldItem = a_Player:GetEquippedItem();
-if (cItemCategory:IsShovel(HeldItem.m_ItemType)) then
+local HeldItem = a_Player:GetEquippedItem()
+if (ItemCategory.IsShovel(HeldItem.m_ItemType)) then
 	-- It's a shovel
 end
 
From 49ac6fadfc441e1de1a0127ff45996ac3abae150 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 16:44:36 +0300 Subject: [PATCH 090/102] Fixed spaces after "template" keyword. --- src/Bindings/ManualBindings.cpp | 12 ++++++------ src/Blocks/ClearMetaOnDrop.h | 2 +- src/Blocks/MetaRotator.h | 10 +++++----- src/OSSupport/Queue.h | 2 +- src/StringUtils.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 6b40cece8..23651b0e1 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -301,11 +301,11 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) -template< +template < class Ty1, class Ty2, bool (Ty1::*Func1)(const AString &, cItemCallback &) - > +> static int tolua_DoWith(lua_State* tolua_S) { int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ @@ -395,7 +395,7 @@ static int tolua_DoWith(lua_State* tolua_S) -template< +template < class Ty1, class Ty2, bool (Ty1::*Func1)(int, cItemCallback &) @@ -485,7 +485,7 @@ static int tolua_DoWithID(lua_State* tolua_S) -template< +template < class Ty1, class Ty2, bool (Ty1::*Func1)(int, int, int, cItemCallback &) @@ -580,7 +580,7 @@ static int tolua_DoWithXYZ(lua_State* tolua_S) -template< +template < class Ty1, class Ty2, bool (Ty1::*Func1)(int, int, cItemCallback &) @@ -676,7 +676,7 @@ static int tolua_ForEachInChunk(lua_State * tolua_S) -template< +template < class Ty1, class Ty2, bool (Ty1::*Func1)(cItemCallback &) diff --git a/src/Blocks/ClearMetaOnDrop.h b/src/Blocks/ClearMetaOnDrop.h index f2afbc6ea..aa4f23848 100644 --- a/src/Blocks/ClearMetaOnDrop.h +++ b/src/Blocks/ClearMetaOnDrop.h @@ -7,7 +7,7 @@ // For example to use in class Foo which should inherit Bar use // class Foo : public cClearMetaOnDrop; -template +template class cClearMetaOnDrop : public Base { public: diff --git a/src/Blocks/MetaRotator.h b/src/Blocks/MetaRotator.h index 599aa7ef9..4c268077a 100644 --- a/src/Blocks/MetaRotator.h +++ b/src/Blocks/MetaRotator.h @@ -20,7 +20,7 @@ Usage: Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state. */ -template +template class cMetaRotator : public Base { public: @@ -41,7 +41,7 @@ public: -template +template NIBBLETYPE cMetaRotator::MetaRotateCW(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); @@ -63,7 +63,7 @@ NIBBLETYPE cMetaRotator +template NIBBLETYPE cMetaRotator::MetaRotateCCW(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); @@ -85,7 +85,7 @@ NIBBLETYPE cMetaRotator +template NIBBLETYPE cMetaRotator::MetaMirrorXY(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); @@ -102,7 +102,7 @@ NIBBLETYPE cMetaRotator +template NIBBLETYPE cMetaRotator::MetaMirrorYZ(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); diff --git a/src/OSSupport/Queue.h b/src/OSSupport/Queue.h index bf4d7f004..8d096fe29 100644 --- a/src/OSSupport/Queue.h +++ b/src/OSSupport/Queue.h @@ -20,7 +20,7 @@ cQueueFuncs and is used as the default behavior. */ /// This empty struct allows for the callback functions to be inlined -template +template struct cQueueFuncs { public: diff --git a/src/StringUtils.h b/src/StringUtils.h index a78f8b0bf..7699a18bd 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -101,7 +101,7 @@ extern int GetBEInt(const char * a_Mem); extern void SetBEInt(char * a_Mem, Int32 a_Value); /// Parses any integer type. Checks bounds and returns errors out of band. -template +template bool StringToInteger(const AString& a_str, T& a_Num) { size_t i = 0; From 9b68ff2656d5e662d33c670ee5fa20dd12b8264f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 16:53:26 +0300 Subject: [PATCH 091/102] CheckBasicStyle: Added checking for the "template" keyword. --- src/CheckBasicStyle.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index bf81a7cd5..b244b1fbc 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -108,7 +108,7 @@ local g_ViolationPatterns = -- Check that all commas have spaces after them and not in front of them: {" ,", "Extra space before a \",\""}, - {",[^%s\"%%]", "Needs a space after a \",\""}, -- Report all except >> "," << needed for splitting and >>,%s<< needed for formatting + {",[^%s\"%%\']", "Needs a space after a \",\""}, -- Report all except >> "," << needed for splitting and >>,%s<< needed for formatting -- Check that opening braces are not at the end of a code line: {"[^%s].-{\n?$", "Brace should be on a separate line"}, @@ -119,6 +119,7 @@ local g_ViolationPatterns = {"while%(", "Needs a space after \"while\""}, {"switch%(", "Needs a space after \"switch\""}, {"catch%(", "Needs a space after \"catch\""}, + {"template<", "Needs a space after \"template\""}, -- No space after keyword's parenthesis: {"[^%a#]if %( ", "Remove the space after \"(\""}, From 271c8c0d3246749087f9772df31896d93f2cb9f3 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 16:58:48 +0300 Subject: [PATCH 092/102] More template keyword fixes. --- src/BlockArea.cpp | 18 +++++++++--------- src/BlockArea.h | 2 +- src/Defines.h | 2 +- src/LinearUpscale.h | 6 +++--- src/StringUtils.h | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 90f7ca6c9..ba55528b8 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -28,7 +28,7 @@ typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLE // This wild construct allows us to pass a function argument and still have it inlined by the compiler :) /// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function -template +template void InternalMergeBlocks( BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, @@ -74,7 +74,7 @@ void InternalMergeBlocks( /// Combinator used for cBlockArea::msOverwrite merging -template +template void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { a_DstType = a_SrcType; @@ -89,7 +89,7 @@ void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLE /// Combinator used for cBlockArea::msFillAir merging -template +template void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_DstType == E_BLOCK_AIR) @@ -108,7 +108,7 @@ void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETY /// Combinator used for cBlockArea::msImprint merging -template +template void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_SrcType != E_BLOCK_AIR) @@ -127,7 +127,7 @@ void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETY /// Combinator used for cBlockArea::msLake merging -template +template void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // Sponge is the NOP block @@ -201,7 +201,7 @@ void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE /** Combinator used for cBlockArea::msSpongePrint merging */ -template +template void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // Sponge overwrites nothing, everything else overwrites anything @@ -220,7 +220,7 @@ void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB /** Combinator used for cBlockArea::msDifference merging */ -template +template void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta))) @@ -246,7 +246,7 @@ void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBL /** Combinator used for cBlockArea::msMask merging */ -template +template void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // If the blocks are the same, keep the dest; otherwise replace with air @@ -2121,7 +2121,7 @@ void cBlockArea::RelSetData( -template +template void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas) { // Block types are compulsory, block metas are voluntary diff --git a/src/BlockArea.h b/src/BlockArea.h index a95ba7788..86f7c4f2d 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -362,7 +362,7 @@ protected: NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight ); - template + template void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas); // tolua_begin } ; diff --git a/src/Defines.h b/src/Defines.h index 0981077c4..78c58034e 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -528,7 +528,7 @@ inline float GetSpecialSignf( float a_Val) -template inline T Diff(T a_Val1, T a_Val2) +template inline T Diff(T a_Val1, T a_Val2) { return std::abs(a_Val1 - a_Val2); } diff --git a/src/LinearUpscale.h b/src/LinearUpscale.h index 0b04408cf..a49f4bdf9 100644 --- a/src/LinearUpscale.h +++ b/src/LinearUpscale.h @@ -31,7 +31,7 @@ Linearly interpolates values in the array between the equidistant anchor points Works in-place (input is already present at the correct output coords) Uses templates to make it possible for the compiler to further optimizer the loops */ -template< +template < int SizeX, int SizeY, // Dimensions of the array int AnchorStepX, int AnchorStepY, typename TYPE @@ -83,7 +83,7 @@ void LinearUpscale2DArrayInPlace(TYPE * a_Array) Linearly interpolates values in the array between the equidistant anchor points (upscales). Works on two arrays, input is packed and output is to be completely constructed. */ -template void LinearUpscale2DArray( +template void LinearUpscale2DArray( TYPE * a_Src, ///< Source array of size a_SrcSizeX x a_SrcSizeY int a_SrcSizeX, int a_SrcSizeY, ///< Dimensions of the src array TYPE * a_Dst, ///< Dest array, of size (a_SrcSizeX * a_UpscaleX + 1) x (a_SrcSizeY * a_UpscaleY + 1) @@ -153,7 +153,7 @@ template void LinearUpscale2DArray( Linearly interpolates values in the array between the equidistant anchor points (upscales). Works on two arrays, input is packed and output is to be completely constructed. */ -template void LinearUpscale3DArray( +template void LinearUpscale3DArray( TYPE * a_Src, ///< Source array of size a_SrcSizeX x a_SrcSizeY x a_SrcSizeZ int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, ///< Dimensions of the src array TYPE * a_Dst, ///< Dest array, of size (a_SrcSizeX * a_UpscaleX + 1) x (a_SrcSizeY * a_UpscaleY + 1) x (a_SrcSizeZ * a_UpscaleZ + 1) diff --git a/src/StringUtils.h b/src/StringUtils.h index a63d852ee..4a4c267c7 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -117,7 +117,7 @@ bool StringToInteger(const AString& a_str, T& a_Num) } if (positive) { - for(size_t size = a_str.size(); i < size; i++) + for (size_t size = a_str.size(); i < size; i++) { if ((a_str[i] <= '0') || (a_str[i] >= '9')) { @@ -138,7 +138,7 @@ bool StringToInteger(const AString& a_str, T& a_Num) } else { - for(size_t size = a_str.size(); i < size; i++) + for (size_t size = a_str.size(); i < size; i++) { if ((a_str[i] <= '0') || (a_str[i] >= '9')) { From d74e49ddc00095589cfefb29ceb23da13f3e5f0a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 17:01:59 +0300 Subject: [PATCH 093/102] Final template keyword style fix. --- src/AllocationPool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AllocationPool.h b/src/AllocationPool.h index 3c9dbe8c9..61431a548 100644 --- a/src/AllocationPool.h +++ b/src/AllocationPool.h @@ -3,7 +3,7 @@ #include -template +template class cAllocationPool { public: @@ -34,7 +34,7 @@ public: /** Allocates memory storing unused elements in a linked list. Keeps at least NumElementsInReserve elements in the list unless malloc fails so that the program has a reserve to handle OOM.**/ -template +template class cListAllocationPool : public cAllocationPool { public: From 1c136a60478811dabfb54e89a27fb1229d0d1b49 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 17:04:26 +0300 Subject: [PATCH 094/102] Fixed a typo. --- src/Entities/Minecart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index f43c4d163..21c58fdba 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -906,7 +906,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) } else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) { - // Moving +X -T + // Moving +X -Z // ~ SpeedX <= 0 Immobile or not moving in the "right" direction AddSpeedX(4 / sqrt(2)); AddSpeedZ(-4 / sqrt(2)); From eaf33e22cf65178d94aafab3df5d8a9f67581529 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 18:57:56 +0200 Subject: [PATCH 095/102] Fixed anvil placing. --- src/Blocks/BlockAnvil.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 5c4661c11..376bf86a3 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -40,14 +40,15 @@ public: ) override { a_BlockType = m_BlockType; - NIBBLETYPE HighBits = a_BlockMeta & 0x0c; // Only highest two bits are preserved + NIBBLETYPE Meta = a_Player->GetEquippedItem().m_ItemDamage; int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3; + switch (Direction) { - case 0: a_BlockMeta = 0x2 | HighBits; break; - case 1: a_BlockMeta = 0x3 | HighBits; break; - case 2: a_BlockMeta = 0x0 | HighBits; break; - case 3: a_BlockMeta = 0x1 | HighBits; break; + case 0: a_BlockMeta = 0x2 | Meta << 2; break; + case 1: a_BlockMeta = 0x3 | Meta << 2; break; + case 2: a_BlockMeta = 0x0 | Meta << 2; break; + case 3: a_BlockMeta = 0x1 | Meta << 2; break; default: { return false; From 4470ebffd72a091cddc46022bb3f5ed378651584 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 20:49:34 +0200 Subject: [PATCH 096/102] Fire can be destroyed with the sword in creative-mode --- src/ClientHandle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8aa883144..f9c6a664c 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1059,7 +1059,8 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc if ( m_Player->IsGameModeCreative() && - ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType) + ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType) && + (m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_FIRE) ) { // Players can't destroy blocks with a Sword in the hand. From c4d7f7996b0dcd784f5e1ccc8553b062c3ac96b6 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Fri, 29 Aug 2014 00:42:33 +0200 Subject: [PATCH 097/102] Hotfixed recipe.txt loading. --- MCServer/crafting.txt | 2 +- src/CraftingRecipes.cpp | 7 +++++-- src/StringUtils.h | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt index 60cda0673..684294bb3 100644 --- a/MCServer/crafting.txt +++ b/MCServer/crafting.txt @@ -84,7 +84,7 @@ BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1 StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1 NetherbrickSlab, 6 = NetherBrick, 1:1, 2:1, 3:1 Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1 -snow, 6 = SnowBlock, 1:1, 2:1, 3:1 +snow, 6 = SnowBlock, 1:1, 2:1, 3:1 # Stairs: WoodStairs, 4 = Planks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 2d80ecaf8..223184c64 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -1,4 +1,4 @@ - + // CraftingRecipes.cpp // Interfaces to the cCraftingRecipes class representing the storage of crafting recipes @@ -366,7 +366,10 @@ void cCraftingRecipes::ClearRecipes(void) void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine) { - AStringVector Sides = StringSplit(a_RecipeLine, "="); + AString RecipeLine(a_RecipeLine); + RecipeLine.erase(std::remove(RecipeLine.begin(), RecipeLine.end(), ' '), RecipeLine.end()); + + AStringVector Sides = StringSplit(RecipeLine, "="); if (Sides.size() != 2) { LOGWARNING("crafting.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1); diff --git a/src/StringUtils.h b/src/StringUtils.h index 4a4c267c7..c48ca6051 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -119,7 +119,7 @@ bool StringToInteger(const AString& a_str, T& a_Num) { for (size_t size = a_str.size(); i < size; i++) { - if ((a_str[i] <= '0') || (a_str[i] >= '9')) + if ((a_str[i] < '0') || (a_str[i] > '9')) { return false; } @@ -140,7 +140,7 @@ bool StringToInteger(const AString& a_str, T& a_Num) { for (size_t size = a_str.size(); i < size; i++) { - if ((a_str[i] <= '0') || (a_str[i] >= '9')) + if ((a_str[i] < '0') || (a_str[i] > '9')) { return false; } From 42570cbeef6a3634f56c54008277c395edaa041e Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 11:20:23 +0300 Subject: [PATCH 098/102] Fixed spaces. --- src/StringUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StringUtils.h b/src/StringUtils.h index c48ca6051..72a90a8c2 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -101,7 +101,7 @@ extern void SetBEInt(char * a_Mem, Int32 a_Value); /// Parses any integer type. Checks bounds and returns errors out of band. template -bool StringToInteger(const AString& a_str, T& a_Num) +bool StringToInteger(const AString & a_str, T & a_Num) { size_t i = 0; bool positive = true; From 97c4c057e4e818562ae0a75520923196044ed55b Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 11:20:33 +0300 Subject: [PATCH 099/102] Fixed conversion warning. --- src/Blocks/BlockAnvil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 376bf86a3..20514580e 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -40,7 +40,7 @@ public: ) override { a_BlockType = m_BlockType; - NIBBLETYPE Meta = a_Player->GetEquippedItem().m_ItemDamage; + NIBBLETYPE Meta = (NIBBLETYPE)a_Player->GetEquippedItem().m_ItemDamage; int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3; switch (Direction) From d0551e2e0a98a28f31a88d489d17b408e4a7d38d Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 14:58:41 +0300 Subject: [PATCH 100/102] VanillaFluidSimulator: Fixed an invalid Y-coord query. This was causing a spam of console messages, along with possible server crash, when liquids passed below the world: http://forum.mc-server.org/showthread.php?tid=1508&pid=15632#pid15632 --- src/Simulator/VanillaFluidSimulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp index 18d9b07e1..6df75eebb 100644 --- a/src/Simulator/VanillaFluidSimulator.cpp +++ b/src/Simulator/VanillaFluidSimulator.cpp @@ -98,7 +98,7 @@ int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int } // Check if block below is passable - if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta)) + if ((a_RelY > 0) && !a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta)) { return Cost; } From 22e3bbd0db71f9bd6d0a4306db1127f257bd24b1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 19:19:27 +0300 Subject: [PATCH 101/102] Rewritten block entity loading. Block entities are now loaded based on the blocktype at the coords they specify; before loading, their type ("id" NBT tag) is checked. The chunk now expects that all block entities given to it via cChunk::SetAllData() have their valid blocktype; asserts if they don't. Fixes #1354. --- src/Chunk.cpp | 10 + src/Chunk.h | 2 +- src/SetChunkData.cpp | 33 +++ src/SetChunkData.h | 3 + src/World.cpp | 6 +- src/WorldStorage/WSSAnvil.cpp | 468 ++++++++++++++++++---------------- src/WorldStorage/WSSAnvil.h | 31 ++- 7 files changed, 323 insertions(+), 230 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 116c0f3a0..40ffff834 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -296,6 +296,16 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData) } m_BlockEntities.clear(); std::swap(a_SetChunkData.GetBlockEntities(), m_BlockEntities); + + // Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only): + #ifdef _DEBUG + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) + { + BLOCKTYPE EntityBlockType = (*itr)->GetBlockType(); + BLOCKTYPE WorldBlockType = GetBlock((*itr)->GetRelX(), (*itr)->GetPosY(), (*itr)->GetRelZ()); + ASSERT(EntityBlockType == WorldBlockType); + } // for itr - m_BlockEntities + #endif // _DEBUG // Set all block entities' World variable: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) diff --git a/src/Chunk.h b/src/Chunk.h index 72a1f6c95..e7aeff1a4 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -155,7 +155,7 @@ public: void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const; - BLOCKTYPE GetBlock(Vector3i a_cords) const { return GetBlock(a_cords.x, a_cords.y, a_cords.z);} + BLOCKTYPE GetBlock(Vector3i a_RelCords) const { return GetBlock(a_RelCords.x, a_RelCords.y, a_RelCords.z);} void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index af6ad1251..97903074a 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "SetChunkData.h" +#include "BlockEntities/BlockEntity.h" @@ -116,3 +117,35 @@ void cSetChunkData::CalculateHeightMap(void) + +void cSetChunkData::RemoveInvalidBlockEntities(void) +{ + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) + { + BLOCKTYPE EntityBlockType = (*itr)->GetBlockType(); + BLOCKTYPE WorldBlockType = cChunkDef::GetBlock(m_BlockTypes, (*itr)->GetRelX(), (*itr)->GetPosY(), (*itr)->GetRelZ()); + if (EntityBlockType != WorldBlockType) + { + // Bad blocktype, remove the block entity: + LOGD("Block entity blocktype mismatch at {%d, %d, %d}: entity for blocktype %s(%d) in block %s(%d). Deleting the block entity.", + (*itr)->GetPosX(), (*itr)->GetPosY(), (*itr)->GetPosZ(), + ItemTypeToString(EntityBlockType).c_str(), EntityBlockType, + ItemTypeToString(WorldBlockType).c_str(), WorldBlockType + ); + cBlockEntityList::iterator itr2 = itr; + itr2++; + m_BlockEntities.erase(itr); + delete *itr; + itr = itr2; + } + else + { + // Good blocktype, keep the block entity: + ++itr; + } + } // for itr - m_BlockEntities[] +} + + + + diff --git a/src/SetChunkData.h b/src/SetChunkData.h index a2f776f6b..03e9ef4d9 100644 --- a/src/SetChunkData.h +++ b/src/SetChunkData.h @@ -92,6 +92,9 @@ public: /** Calculates the heightmap based on the contained blocktypes and marks it valid. */ void CalculateHeightMap(void); + /** Removes the block entities that don't have a proper blocktype at their corresponding coords. */ + void RemoveInvalidBlockEntities(void); + protected: int m_ChunkX; int m_ChunkZ; diff --git a/src/World.cpp b/src/World.cpp index 69d1217f1..b01e53638 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3484,14 +3484,16 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cChunkDef::BlockNibbles BlockMetas; a_ChunkDesc.CompressBlockMetas(BlockMetas); - m_World->QueueSetChunkData(cSetChunkDataPtr(new cSetChunkData( + cSetChunkDataPtr SetChunkData(new cSetChunkData( 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 - ))); + )); + SetChunkData->RemoveInvalidBlockEntities(); + m_World->QueueSetChunkData(SetChunkData); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index a9c9ae4b5..5978e5ef8 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -396,7 +396,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } // for y //*/ - m_World->QueueSetChunkData(cSetChunkDataPtr(new cSetChunkData( + cSetChunkDataPtr SetChunkData(new cSetChunkData( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : NULL, @@ -404,7 +404,8 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT NULL, Biomes, Entities, BlockEntities, false - ))); + )); + m_World->QueueSetChunkData(SetChunkData); return true; } @@ -581,64 +582,32 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { continue; } - int sID = a_NBT.FindChildByName(Child, "id"); - if (sID < 0) + + // Get the BlockEntity's position + int x, y, z; + if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z)) + { + LOGWARNING("Bad block entity, missing the coords. Will be ignored."); + continue; + } + int RelX = x, RelY = y, RelZ = z, ChunkX, ChunkZ; + cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ); + if (RelY == 2) + { + LOGD("HERE"); + } + + // Load the proper BlockEntity type based on the block type: + BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, RelY, RelZ); + NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, RelY, RelZ); + std::auto_ptr be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta)); + if (be.get() == NULL) { continue; } - if (strncmp(a_NBT.GetData(sID), "Beacon", a_NBT.GetDataLength(sID)) == 0) - { - LoadBeaconFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0) - { - LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_CHEST); - } - else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0) - { - LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0) - { - LoadDropperFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "FlowerPot", a_NBT.GetDataLength(sID)) == 0) - { - LoadFlowerPotFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0) - { - LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child, a_BlockTypes, a_BlockMetas); - } - else if (strncmp(a_NBT.GetData(sID), "Hopper", a_NBT.GetDataLength(sID)) == 0) - { - LoadHopperFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Music", a_NBT.GetDataLength(sID)) == 0) - { - LoadNoteFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "RecordPlayer", a_NBT.GetDataLength(sID)) == 0) - { - LoadJukeboxFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Sign", a_NBT.GetDataLength(sID)) == 0) - { - LoadSignFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Skull", a_NBT.GetDataLength(sID)) == 0) - { - LoadMobHeadFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "Trap", a_NBT.GetDataLength(sID)) == 0) - { - LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child); - } - else if (strncmp(a_NBT.GetData(sID), "TrappedChest", a_NBT.GetDataLength(sID)) == 0) - { - LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_TRAPPED_CHEST); - } - // TODO: Other block entities + + // Add the BlockEntity to the loaded data: + a_BlockEntities.push_back(be.release()); } // for Child - tag children } @@ -646,6 +615,52 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con +cBlockEntity * cWSSAnvil::LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a_Tag, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + // Load the specific BlockEntity type: + switch (a_BlockType) + { + // Specific entity loaders: + case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_CHEST); + case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT(a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FURNACE, a_BlockMeta); + case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LIT_FURNACE, a_BlockMeta); + case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ); + case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SIGN_POST); + case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_TRAPPED_CHEST); + case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WALLSIGN); + + // Blocktypes that have block entities but don't load their contents from disk: + case E_BLOCK_ENDER_CHEST: return NULL; + } + + // All the other blocktypes should have no entities assigned to them. Report an error: + // Get the "id" tag: + int TagID = a_NBT.FindChildByName(a_Tag, "id"); + AString TypeName(""); + if (TagID >= 0) + { + TypeName.assign(a_NBT.GetData(TagID), (size_t)a_NBT.GetDataLength(TagID)); + } + LOGINFO("WorldLoader(%s): Block entity mismatch: block type %s (%d), type \"%s\", at {%d, %d, %d}; the entity will be lost.", + m_World->GetName().c_str(), + ItemTypeToString(a_BlockType).c_str(), a_BlockType, TypeName.c_str(), + a_BlockX, a_BlockY, a_BlockZ + ); + return NULL; +} + + + + + bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx) { int Type = a_NBT.FindChildByName(a_TagIdx, "id"); @@ -656,7 +671,6 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ a_Item.m_ItemType = a_NBT.GetShort(Type); if (a_Item.m_ItemType < 0) { - LOGD("Encountered an item with negative type (%d). Replacing with an empty item.", a_NBT.GetShort(Type)); a_Item.Empty(); return true; } @@ -754,16 +768,46 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a -void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the given tag is a compound: + if (a_NBT.GetType(a_TagIdx) != TAG_Compound) { - return; + return false; } - std::auto_ptr Beacon(new cBeaconEntity(x, y, z, m_World)); + // Get the "id" tag: + int TagID = a_NBT.FindChildByName(a_TagIdx, "id"); + if (TagID < 0) + { + return false; + } + + // Compare the value: + if (strncmp(a_NBT.GetData(TagID), a_ExpectedType, (size_t)a_NBT.GetDataLength(TagID)) == 0) + { + return true; + } + LOGWARNING("Block entity type mismatch: exp \"%s\", got \"%s\".", + a_ExpectedType, + AString(a_NBT.GetData(TagID), (size_t)a_NBT.GetDataLength(TagID)).c_str() + ); + return false; +} + + + + + +cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Beacon")) + { + return NULL; + } + + std::auto_ptr Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels"); if (CurrentLine >= 0) @@ -790,88 +834,128 @@ void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cPar LoadItemGridFromNBT(Beacon->GetContents(), a_NBT, Items); } - a_BlockEntities.push_back(Beacon.release()); + return Beacon.release(); } -void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType) +cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_ChestBlockType) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + // TODO: Does vanilla use "TrappedChest" or not? MCWiki says no, but previous code says yes + // Ref.: http://minecraft.gamepedia.com/Trapped_Chest + // https://github.com/mc-server/MCServer/blob/d0551e2e0a98a28f31a88d489d17b408e4a7d38d/src/WorldStorage/WSSAnvil.cpp#L637 + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Chest") && !CheckBlockEntityType(a_NBT, a_TagIdx, "TrappedChest")) { - return; + return NULL; } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this + return NULL; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this } - std::auto_ptr Chest(new cChestEntity(x, y, z, m_World, a_ChestType)); + std::auto_ptr Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType)); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); - a_BlockEntities.push_back(Chest.release()); + return Chest.release(); } -void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Control")) { - return; + return NULL; } + + std::auto_ptr CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + + int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); + if (currentLine >= 0) + { + CmdBlock->SetCommand(a_NBT.GetString(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount"); + if (currentLine >= 0) + { + CmdBlock->SetResult(a_NBT.GetInt(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput"); + if (currentLine >= 0) + { + CmdBlock->SetLastOutput(a_NBT.GetString(currentLine)); + } + + // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it. + + return CmdBlock.release(); +} + + + + + +cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Trap")) + { + return NULL; + } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this + return NULL; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this } - std::auto_ptr Dispenser(new cDispenserEntity(x, y, z, m_World)); + std::auto_ptr Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items); - a_BlockEntities.push_back(Dispenser.release()); + return Dispenser.release(); } -void cWSSAnvil::LoadDropperFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Dropper")) { - return; + return NULL; } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this + return NULL; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this } - std::auto_ptr Dropper(new cDropperEntity(x, y, z, m_World)); + std::auto_ptr Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); - a_BlockEntities.push_back(Dropper.release()); + return Dropper.release(); } -void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "FlowerPot")) { - return; + return NULL; } - std::auto_ptr FlowerPot(new cFlowerPotEntity(x, y, z, m_World)); + + std::auto_ptr FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); short ItemType = 0, ItemData = 0; int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item"); @@ -887,37 +971,28 @@ void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const c } FlowerPot->SetItem(cItem(ItemType, 1, ItemData)); - a_BlockEntities.push_back(FlowerPot.release()); + return FlowerPot.release(); } -void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas) +cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Furnace")) { - return; + return NULL; } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this + return NULL; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this } - // Convert coords to relative: - int RelX = x; - int RelZ = z; - int ChunkX, ChunkZ; - cChunkDef::AbsoluteToRelative(RelX, y, RelZ, ChunkX, ChunkZ); - - // Create the furnace entity, with proper BlockType and BlockMeta info: - BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, y, RelZ); - NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, y, RelZ); - std::auto_ptr Furnace(new cFurnaceEntity(x, y, z, BlockType, BlockMeta, m_World)); + std::auto_ptr Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World)); // Load slots: for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child)) @@ -954,86 +1029,121 @@ void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cPa // Restart cooking: Furnace->ContinueCooking(); - a_BlockEntities.push_back(Furnace.release()); + return Furnace.release(); } -void cWSSAnvil::LoadHopperFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Hopper")) { - return; + return NULL; } + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) { - return; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this + return NULL; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this } - std::auto_ptr Hopper(new cHopperEntity(x, y, z, m_World)); + std::auto_ptr Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items); - a_BlockEntities.push_back(Hopper.release()); + return Hopper.release(); } -void cWSSAnvil::LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "RecordPlayer")) { - return; + return NULL; } - std::auto_ptr Jukebox(new cJukeboxEntity(x, y, z, m_World)); + + std::auto_ptr Jukebox(new cJukeboxEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int Record = a_NBT.FindChildByName(a_TagIdx, "Record"); if (Record >= 0) { Jukebox->SetRecord(a_NBT.GetInt(Record)); } - a_BlockEntities.push_back(Jukebox.release()); + return Jukebox.release(); } -void cWSSAnvil::LoadNoteFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Skull")) { - return; + return NULL; } - std::auto_ptr Note(new cNoteEntity(x, y, z, m_World)); + + std::auto_ptr MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); + + int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType"); + if (currentLine >= 0) + { + MobHead->SetType(static_cast(a_NBT.GetByte(currentLine))); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot"); + if (currentLine >= 0) + { + MobHead->SetRotation(static_cast(a_NBT.GetByte(currentLine))); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType"); + if (currentLine >= 0) + { + MobHead->SetOwner(a_NBT.GetString(currentLine)); + } + + return MobHead.release(); +} + + + + + +cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Music")) + { + return NULL; + } + + std::auto_ptr NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World)); int note = a_NBT.FindChildByName(a_TagIdx, "note"); if (note >= 0) { - Note->SetPitch(a_NBT.GetByte(note)); + NoteBlock->SetPitch(a_NBT.GetByte(note)); } - a_BlockEntities.push_back(Note.release()); + return NoteBlock.release(); } -void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) { - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + // Check if the data has a proper type: + if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Sign")) { - return; + return NULL; } - std::auto_ptr Sign(new cSignEntity(E_BLOCK_SIGN_POST, x, y, z, m_World)); + + std::auto_ptr Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World)); int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1"); if (currentLine >= 0) @@ -1059,79 +1169,7 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse Sign->SetLine(3, a_NBT.GetString(currentLine)); } - a_BlockEntities.push_back(Sign.release()); -} - - - - - -void cWSSAnvil::LoadMobHeadFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) -{ - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) - { - return; - } - std::auto_ptr MobHead(new cMobHeadEntity(x, y, z, m_World)); - - int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType"); - if (currentLine >= 0) - { - MobHead->SetType(static_cast(a_NBT.GetByte(currentLine))); - } - - currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot"); - if (currentLine >= 0) - { - MobHead->SetRotation(static_cast(a_NBT.GetByte(currentLine))); - } - - currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType"); - if (currentLine >= 0) - { - MobHead->SetOwner(a_NBT.GetString(currentLine)); - } - - a_BlockEntities.push_back(MobHead.release()); -} - - - - - -void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) -{ - ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); - int x, y, z; - if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) - { - return; - } - std::auto_ptr CmdBlock(new cCommandBlockEntity(x, y, z, m_World)); - - int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); - if (currentLine >= 0) - { - CmdBlock->SetCommand(a_NBT.GetString(currentLine)); - } - - currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount"); - if (currentLine >= 0) - { - CmdBlock->SetResult(a_NBT.GetInt(currentLine)); - } - - currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput"); - if (currentLine >= 0) - { - CmdBlock->SetLastOutput(a_NBT.GetString(currentLine)); - } - - // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it. - - a_BlockEntities.push_back(CmdBlock.release()); + return Sign.release(); } diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index a41268f4c..591ec6757 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -125,6 +125,10 @@ protected: /// Loads the chunk's BlockEntities from NBT data (a_Tag is the Level\\TileEntities list tag; may be -1) void LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntitites, const cParsedNBT & a_NBT, int a_Tag, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); + /** Loads the data for a block entity from the specified NBT tag. + Returns the loaded block entity, or NULL upon failure. */ + cBlockEntity * LoadBlockEntityFromNBT(const cParsedNBT & a_NBT, int a_Tag, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + /// Loads a cItem contents from the specified NBT tag; returns true if successful. Doesn't load the Slot tag bool LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx); @@ -134,18 +138,21 @@ protected: */ void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); - void LoadBeaconFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType); - void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); - void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadMobHeadFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + /** Returns true iff the "id" child tag inside the specified tag equals the specified expected type. */ + bool CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType); + + cBlockEntity * LoadBeaconFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadChestFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_ChestBlockType); + cBlockEntity * LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadDispenserFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadDropperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadFlowerPotFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadFurnaceFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + cBlockEntity * LoadHopperFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadJukeboxFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadMobHeadFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadNoteBlockFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ); + cBlockEntity * LoadSignFromNBT (const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SignBlockType); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength); From a2bee74a13989f725e8f8ca3ffe967e157f8d77f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 23:21:58 +0300 Subject: [PATCH 102/102] cChunk: Fixed the Coords param. --- src/Chunk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chunk.h b/src/Chunk.h index e7aeff1a4..e5de22e3b 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -155,7 +155,7 @@ public: void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const; - BLOCKTYPE GetBlock(Vector3i a_RelCords) const { return GetBlock(a_RelCords.x, a_RelCords.y, a_RelCords.z);} + BLOCKTYPE GetBlock(const Vector3i & a_RelCoords) const { return GetBlock(a_RelCoords.x, a_RelCoords.y, a_RelCoords.z); } void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);