From 9f03682258d949b3b6ddd4fedec93977dedbadde Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Thu, 29 May 2014 13:34:38 +0200 Subject: [PATCH 001/751] Enderman attacks a player if he's looking at him. --- src/Mobs/Enderman.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++ src/Mobs/Enderman.h | 1 + 2 files changed, 91 insertions(+) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index becc99a86..bd5ed85f1 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -2,6 +2,66 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Enderman.h" +#include "../Entities/Player.h" + + + + +/////////////////////////////////////////////////////////////////////////// +// cPlayerLookCheck +class cPlayerLookCheck : + public cPlayerListCallback +{ +public: + cPlayerLookCheck(Vector3d a_EndermanPos) : + m_EndermanPos(a_EndermanPos), + m_Player(NULL) + { + } + + virtual bool Item(cPlayer * a_Player) override + { + // Don't check players who are in creative gamemode. + if (a_Player->IsGameModeCreative()) + { + return false; + } + + Vector3d Direction = m_EndermanPos - a_Player->GetPosition(); + + // Don't check players who are more then 64 blocks away. + if (Direction.SqrLength() > 64) + { + return false; + } + + // Don't check if the player has a pumpkin on his head. + if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN) + { + return false; + } + + Direction.Normalize(); + + Vector3d LookVector = a_Player->GetLookVector(); + LookVector.Normalize(); + + if ((Direction - LookVector).SqrLength() > 0.02) + { + return false; + } + + // TODO: Don't attack the player if there is a wall between the player and the enderman. + m_Player = a_Player; + return true; + } + + cPlayer * GetPlayer(void) const {return m_Player;} + bool HasFoundPlayer(void) const {return (m_Player != NULL);} +protected: + cPlayer * m_Player; + Vector3d m_EndermanPos; +} ; @@ -32,3 +92,33 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer) +void cEnderman::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + if (m_Target != NULL) + { + return; + } + + cPlayerLookCheck Callback(GetPosition()); + if (!m_World->ForEachPlayer(Callback)) + { + return; + } + + if (!Callback.HasFoundPlayer()) + { + return; + } + + m_bIsScreaming = true; + m_Target = Callback.GetPlayer(); + + m_World->BroadcastEntityMetadata(*this); +} + + + + + diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h index 32e40e70b..be6e7bdf4 100644 --- a/src/Mobs/Enderman.h +++ b/src/Mobs/Enderman.h @@ -18,6 +18,7 @@ public: CLASS_PROTODEF(cEnderman); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; bool IsScreaming(void) const {return m_bIsScreaming; } BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; } From 806130a967685b0708b51afc576df09d70d47d79 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Thu, 29 May 2014 14:00:12 +0200 Subject: [PATCH 002/751] Swapped m_Player and m_EndermanPos --- src/Mobs/Enderman.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index bd5ed85f1..40782d0b0 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -14,8 +14,8 @@ class cPlayerLookCheck : { public: cPlayerLookCheck(Vector3d a_EndermanPos) : - m_EndermanPos(a_EndermanPos), - m_Player(NULL) + m_Player(NULL), + m_EndermanPos(a_EndermanPos) { } From 5d4f70a7a52e986343bddde2104f07c797c574c9 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 4 Jun 2014 09:19:55 +0100 Subject: [PATCH 003/751] Improved Enderman code --- src/Mobs/Enderman.cpp | 45 ++++++++++++++++++++++++++++++------------- src/Mobs/Enderman.h | 3 ++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 40782d0b0..416b541ed 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -3,6 +3,7 @@ #include "Enderman.h" #include "../Entities/Player.h" +#include "../Tracer.h" @@ -51,13 +52,19 @@ public: return false; } - // TODO: Don't attack the player if there is a wall between the player and the enderman. + cTracer LineOfSight(a_Player->GetWorld()); + if (LineOfSight.Trace(m_EndermanPos, Direction, (int)Direction.Length())) + { + // No direct line of sight + return false; + } + m_Player = a_Player; return true; } - cPlayer * GetPlayer(void) const {return m_Player;} - bool HasFoundPlayer(void) const {return (m_Player != NULL);} + cPlayer * GetPlayer(void) const { return m_Player; } + protected: cPlayer * m_Player; Vector3d m_EndermanPos; @@ -92,33 +99,45 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer) -void cEnderman::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - +void cEnderman::CheckEventSeePlayer() +{ if (m_Target != NULL) { return; } cPlayerLookCheck Callback(GetPosition()); - if (!m_World->ForEachPlayer(Callback)) + if (m_World->ForEachPlayer(Callback)) { return; } + + ASSERT(Callback.GetPlayer() != NULL); - if (!Callback.HasFoundPlayer()) + int CX, CZ; + cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, CX, CZ); + if (!GetWorld()->IsChunkLighted(CX, CZ)) { + GetWorld()->QueueLightChunk(CX, CZ); return; } - m_bIsScreaming = true; - m_Target = Callback.GetPlayer(); - - m_World->BroadcastEntityMetadata(*this); + if ((GetWorld()->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() < 15) && !Callback.GetPlayer()->IsGameModeCreative()) + { + super::EventSeePlayer(Callback.GetPlayer()); + m_EMState = CHASING; + m_bIsScreaming = true; + GetWorld()->BroadcastEntityMetadata(*this); + } } +void cEnderman::EventLosePlayer() +{ + super::EventLosePlayer(); + m_bIsScreaming = false; + GetWorld()->BroadcastEntityMetadata(*this); +} \ No newline at end of file diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h index be6e7bdf4..044b40511 100644 --- a/src/Mobs/Enderman.h +++ b/src/Mobs/Enderman.h @@ -18,7 +18,8 @@ public: CLASS_PROTODEF(cEnderman); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void CheckEventSeePlayer(void) override; + virtual void EventLosePlayer(void) override; bool IsScreaming(void) const {return m_bIsScreaming; } BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; } From 0690788cdfefbec3c74057e0b60d9f5aae935303 Mon Sep 17 00:00:00 2001 From: worktycho Date: Wed, 4 Jun 2014 14:16:24 +0100 Subject: [PATCH 004/751] Replaced strange algebra with dot product. 10 degrees is a completely arbitary constant I pulled from nowhere. Feel free to adjust this value. --- src/Mobs/Enderman.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 416b541ed..d26639a75 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -42,12 +42,14 @@ public: return false; } - Direction.Normalize(); Vector3d LookVector = a_Player->GetLookVector(); - LookVector.Normalize(); + double dot = Direction.Dot(LookVector); - if ((Direction - LookVector).SqrLength() > 0.02) + // 0.09 rad ~ 5 degrees. + // If the players crosshars are 10 degrees from the line linking the endermen + // It counts as looking. + if (dot > cos(0.09)) { return false; } @@ -140,4 +142,4 @@ void cEnderman::EventLosePlayer() super::EventLosePlayer(); m_bIsScreaming = false; GetWorld()->BroadcastEntityMetadata(*this); -} \ No newline at end of file +} From afda11a495de5b48ad17334da0e3f3b801d02f9b Mon Sep 17 00:00:00 2001 From: worktycho Date: Mon, 30 Jun 2014 19:33:10 +0100 Subject: [PATCH 005/751] Changed comment --- src/Mobs/Enderman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index d26639a75..6b7a22757 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -47,7 +47,7 @@ public: double dot = Direction.Dot(LookVector); // 0.09 rad ~ 5 degrees. - // If the players crosshars are 10 degrees from the line linking the endermen + // If the players crosshair is within 5 degrees of the endermen // It counts as looking. if (dot > cos(0.09)) { From f79e68266426993af94f811afc8296e7b159462a Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 00:03:00 +0200 Subject: [PATCH 006/751] Fixed plugin count and fixed plugin loading, when settings.ini was regenerated. --- src/Bindings/PluginManager.cpp | 46 ++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 088b92a6d..1d97d1331 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -124,44 +124,58 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) // Check if the Plugins section exists. int KeyNum = a_SettingsIni.FindKey("Plugins"); - // If it does, how many plugins are there? - int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); - if (KeyNum == -1) { InsertDefaultPlugins(a_SettingsIni); + KeyNum = a_SettingsIni.FindKey("Plugins"); } - else if (NumPlugins > 0) + + // How many plugins are there? + int NumPlugins = a_SettingsIni.GetNumValues(KeyNum); + + for (int i = 0; i < NumPlugins; i++) { - for (int i = 0; i < NumPlugins; i++) + AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); + if (ValueName.compare("Plugin") == 0) { - AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); - if (ValueName.compare("Plugin") == 0) + AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); + if (!PluginFile.empty()) { - AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); - if (!PluginFile.empty()) + if (m_Plugins.find(PluginFile) != m_Plugins.end()) { - if (m_Plugins.find(PluginFile) != m_Plugins.end()) - { - LoadPlugin(PluginFile); - } + LoadPlugin(PluginFile); } } } } + + // Remove invalid plugins from the PluginMap. + for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) + { + if (itr->second == NULL) + { + PluginMap::iterator thiz = itr; + ++thiz; + m_Plugins.erase(itr); + itr = thiz; + continue; + } + ++itr; + } + size_t NumLoadedPlugins = GetNumPlugins(); if (NumLoadedPlugins == 0) { LOG("-- No Plugins Loaded --"); } - else if (NumLoadedPlugins > 1) + else if (NumLoadedPlugins == 1) { - LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); + LOG("-- Loaded 1 Plugin --"); } else { - LOG("-- Loaded 1 Plugin --"); + LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); } CallHookPluginsLoaded(); } From a5cca16abe524fdbd756908ac157a0c9881463f3 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 00:39:39 +0200 Subject: [PATCH 007/751] Add "Broadcasting" settings to world.ini --- src/Entities/Player.cpp | 14 ++++++++------ src/Root.cpp | 4 ++-- src/Server.h | 4 ++-- src/World.cpp | 3 +++ src/World.h | 8 +++++++- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fcc8eb9a0..393afc3b6 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -890,7 +890,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! - if (a_TDI.Attacker == NULL) + if ((a_TDI.Attacker == NULL) && m_World->ShouldBroadcastDeathMessages()) { AString DamageText; switch (a_TDI.DamageType) @@ -1208,11 +1208,13 @@ unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) } else { - // First time, announce it - cCompositeChat Msg; - Msg.SetMessageType(mtSuccess); - Msg.AddShowAchievementPart(GetName(), cStatInfo::GetName(a_Ach)); - m_World->BroadcastChat(Msg); + if (m_World->ShouldBroadcastAchievementMessages()) + { + cCompositeChat Msg; + Msg.SetMessageType(mtSuccess); + Msg.AddShowAchievementPart(GetName(), cStatInfo::GetName(a_Ach)); + m_World->BroadcastChat(Msg); + } // Increment the statistic StatValue New = m_Stats.AddValue(a_Ach); diff --git a/src/Root.cpp b/src/Root.cpp index b03a13382..efa21b775 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -269,12 +269,12 @@ void cRoot::LoadWorlds(cIniFile & IniFile) { // First get the default world AString DefaultWorldName = IniFile.GetValueSet("Worlds", "DefaultWorld", "world"); - m_pDefaultWorld = new cWorld( DefaultWorldName.c_str()); + m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds unsigned int KeyNum = IniFile.FindKey("Worlds"); - unsigned int NumWorlds = IniFile.GetNumValues( KeyNum); + unsigned int NumWorlds = IniFile.GetNumValues(KeyNum); if (NumWorlds <= 0) { return; diff --git a/src/Server.h b/src/Server.h index b03359f03..c1640b388 100644 --- a/src/Server.h +++ b/src/Server.h @@ -63,12 +63,12 @@ public: // tolua_export const AString & GetDescription(void) const {return m_Description; } // Player counts: - int GetMaxPlayers(void) const {return m_MaxPlayers; } + int GetMaxPlayers(void) const { return m_MaxPlayers; } int GetNumPlayers(void) const; void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; } // Hardcore mode or not: - bool IsHardcore(void) const {return m_bIsHardcore; } + bool IsHardcore(void) const { return m_bIsHardcore; } // tolua_end diff --git a/src/World.cpp b/src/World.cpp index 7ad350e24..ff393bc2b 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -522,6 +522,9 @@ void cWorld::Start(void) AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); m_Dimension = StringToDimension(Dimension); + m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true); + m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true); + // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); m_IsSpawnExplicitlySet = diff --git a/src/World.h b/src/World.h index 9658178ae..cb77361f6 100644 --- a/src/World.h +++ b/src/World.h @@ -622,7 +622,10 @@ public: bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } - + + bool ShouldBroadcastDeathMessages(void) const { return m_BroadcastDeathMessages; } + bool ShouldBroadcastAchievementMessages(void) const { return m_BroadcastAchievementMessages; } + // tolua_end /** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */ @@ -842,6 +845,9 @@ private: double m_SpawnY; double m_SpawnZ; + bool m_BroadcastDeathMessages; + bool m_BroadcastAchievementMessages; + double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs From 7f9f46c9114837a6edaae53385b7b7970b91abbd Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 13:47:21 +0200 Subject: [PATCH 008/751] Fixed group color's. --- src/ClientHandle.cpp | 19 ++++--------------- src/GroupManager.cpp | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index e4ad218a2..116ea459e 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1973,28 +1973,17 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) { - bool ShouldAppendChatPrefixes = true; - - if (GetPlayer()->GetWorld() == NULL) + cWorld * World = GetPlayer()->GetWorld(); + if (World == NULL) { - cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); + World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); if (World == NULL) { World = cRoot::Get()->GetDefaultWorld(); } - - if (!World->ShouldUseChatPrefixes()) - { - ShouldAppendChatPrefixes = false; - } - } - else if (!GetPlayer()->GetWorld()->ShouldUseChatPrefixes()) - { - ShouldAppendChatPrefixes = false; } - AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData); - + AString Message = FormatMessageType(World->ShouldUseChatPrefixes(), a_ChatPrefix, a_AdditionalData); m_Protocol->SendChat(Message.append(a_Message)); } diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 32c2f1c97..bc9bb67be 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -153,7 +153,7 @@ bool cGroupManager::LoadGroups() AString Color = IniFile.GetValue(KeyName, "Color", "-"); if ((Color != "-") && (Color.length() >= 1)) { - Group->SetColor(cChatColor::Delimiter + Color[0]); + Group->SetColor(cChatColor::Delimiter + Color); } else { From 9be92fa71df5620421c5f64cfa21cb6448a7686c Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 20:44:00 +0200 Subject: [PATCH 009/751] Use Color[0]. --- src/GroupManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index bc9bb67be..e03f8bca3 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -153,7 +153,7 @@ bool cGroupManager::LoadGroups() AString Color = IniFile.GetValue(KeyName, "Color", "-"); if ((Color != "-") && (Color.length() >= 1)) { - Group->SetColor(cChatColor::Delimiter + Color); + Group->SetColor(cChatColor::Delimiter + AString(&Color[0])); } else { From 3d730403278bca630856ce7d275aed920aa20235 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 21:14:45 +0200 Subject: [PATCH 010/751] Use AString(1, Color[0]) --- src/GroupManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index e03f8bca3..f1f86dc0f 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -153,7 +153,7 @@ bool cGroupManager::LoadGroups() AString Color = IniFile.GetValue(KeyName, "Color", "-"); if ((Color != "-") && (Color.length() >= 1)) { - Group->SetColor(cChatColor::Delimiter + AString(&Color[0])); + Group->SetColor(cChatColor::Delimiter + AString(1, Color[0])); } else { From 2bdc2701f4208f5a705fafceec3685a9834714a1 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 27 Jul 2014 21:58:00 +0200 Subject: [PATCH 011/751] Change Group->SetColor() again. --- src/GroupManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index f1f86dc0f..4c3dfc6f0 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -153,7 +153,7 @@ bool cGroupManager::LoadGroups() AString Color = IniFile.GetValue(KeyName, "Color", "-"); if ((Color != "-") && (Color.length() >= 1)) { - Group->SetColor(cChatColor::Delimiter + AString(1, Color[0])); + Group->SetColor(AString(cChatColor::Delimiter) + Color[0]); } else { From f5f9656917c0cb0cc68aee50178aafd3f24c417f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 28 Jul 2014 12:37:48 +0200 Subject: [PATCH 012/751] cAuthenticator: Added GetUUIDsFromPlayerNames(). --- src/Protocol/Authenticator.cpp | 99 ++++++++++++++++++++++++++++++++-- src/Protocol/Authenticator.h | 20 +++++++ 2 files changed, 116 insertions(+), 3 deletions(-) diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 2a7cbc7bc..75721589f 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -17,6 +17,8 @@ #define DEFAULT_AUTH_SERVER "sessionserver.mojang.com" #define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%" +#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com" +#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft" /** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: Downloaded from http://certs.starfieldtech.com/repository/ */ @@ -83,6 +85,8 @@ cAuthenticator::cAuthenticator(void) : super("cAuthenticator"), m_Server(DEFAULT_AUTH_SERVER), m_Address(DEFAULT_AUTH_ADDRESS), + m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER), + m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), m_ShouldAuthenticate(true) { } @@ -102,9 +106,11 @@ cAuthenticator::~cAuthenticator() void cAuthenticator::ReadINI(cIniFile & IniFile) { - m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER); - m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS); + m_Server = IniFile.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER); + m_Address = IniFile.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS); m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); + m_NameToUUIDServer = IniFile.GetValueSet ("Authentication", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); + m_NameToUUIDAddress = IniFile.GetValueSet ("Authentication", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); } @@ -151,6 +157,93 @@ void cAuthenticator::Stop(void) +AStringVector cAuthenticator::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames) +{ + AStringVector res; + + // Create the request body - a JSON containing all the playernames: + Json::Value root; + for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) + { + Json::Value req(*itr); + root.append(req); + } // for itr - a_PlayerNames[] + Json::FastWriter Writer; + AString RequestBody = Writer.write(root); + + // Create the HTTP request: + AString Request; + Request += "POST " + m_NameToUUIDAddress + " HTTP/1.1\r\n"; + Request += "Host: " + m_NameToUUIDServer + "\r\n"; + Request += "User-Agent: MCServer\r\n"; + Request += "Connection: close\r\n"; + Request += "Content-Type: application/json\r\n"; + Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); + Request += "\r\n"; + Request += RequestBody; + + // Get the response from the server: + AString Response; + if (!SecureGetFromAddress(StarfieldCACert(), m_NameToUUIDServer, Request, Response)) + { + return res; + } + + // Check the HTTP status line: + const AString Prefix("HTTP/1.1 200 OK"); + AString HexDump; + if (Response.compare(0, Prefix.size(), Prefix)) + { + LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return res; + } + + // Erase the HTTP headers from the response: + size_t idxHeadersEnd = Response.find("\r\n\r\n"); + if (idxHeadersEnd == AString::npos) + { + LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return res; + } + Response.erase(0, idxHeadersEnd + 4); + + // Parse the returned string into Json: + Json::Reader reader; + if (!reader.parse(Response, root, false) || !root.isArray()) + { + LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); + LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return res; + } + + // Fill in the resulting array; do not expect to get the UUIDs in the same order as the inputs: + size_t len = a_PlayerNames.size(); + size_t JsonCount = root.size(); + res.resize(len); + for (size_t idx = 0; idx < len; idx++) // For each input username... + { + const AString & InputName = a_PlayerNames[idx]; + for (size_t IdxJson = 0; IdxJson < JsonCount; ++IdxJson) + { + Json::Value & Val = root[IdxJson]; + AString JsonName = Val.get("name", "").asString(); + if (NoCaseCompare(JsonName, InputName) == 0) + { + res[idx] = Val.get("id", "").asString(); + break; + } + } // for IdxJson - root[] + } // for idx - a_PlayerNames[] / res[] + + return res; +} + + + + + void cAuthenticator::Execute(void) { for (;;) @@ -307,7 +400,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S a_UUID = root.get("id", "").asString(); a_Properties = root["properties"]; - // If the UUID doesn't contain the hashes, insert them at the proper places: + // If the UUID doesn't contain the dashes, insert them at the proper places: if (a_UUID.size() == 32) { a_UUID.insert(8, "-"); diff --git a/src/Protocol/Authenticator.h b/src/Protocol/Authenticator.h index 244d94c0b..82ecb1f7a 100644 --- a/src/Protocol/Authenticator.h +++ b/src/Protocol/Authenticator.h @@ -52,6 +52,12 @@ public: /** Stops the authenticator thread. The thread may be started and stopped repeatedly */ void Stop(void); + + /** Converts the player names into UUIDs. + a_PlayerName[idx] will be converted to UUID and returned as idx-th value + The UUID will be empty on error. + Blocking operation, do not use in world-tick thread! */ + AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName); private: @@ -76,8 +82,22 @@ private: cUserList m_Queue; cEvent m_QueueNonempty; + /** The server that is to be contacted for auth / UUID conversions */ AString m_Server; + + /** The URL to use for auth, without server part. + %USERNAME% will be replaced with actual user name. + %SERVERID% will be replaced with server's ID. + For example "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%". */ AString m_Address; + + /** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */ + AString m_NameToUUIDServer; + + /** The URL to use for converting player names to UUIDs, without server part. + For example "/profiles/page/1". */ + AString m_NameToUUIDAddress; + AString m_PropertiesAddress; bool m_ShouldAuthenticate; From 1acd03f96f9b1133e1f76d76004f5fcddd0c4788 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 28 Jul 2014 17:09:39 +0200 Subject: [PATCH 013/751] Added cClientHandle:GetUUIDsFromPlayerNames() to Lua API. --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + src/Bindings/ManualBindings.cpp | 65 ++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index e65da1d16..f29c47338 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -529,6 +529,7 @@ end GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." }, GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" }, GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." }, + GetUUIDsFromPlayerNames = { Params = "PlayerNames", Return = "table", Notes = "(STATIC) Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. Queries the Mojang servers for the results. WARNING: Do NOT use this function while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely. NOTE: Mojang API has a limit of 100 names per query and 600 queries per 10 minutes (may change)" }, GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" }, GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" }, HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." }, diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index df9687fc0..28ee00b36 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -26,6 +26,7 @@ #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" #include "../LineBlockTracer.h" +#include "../Protocol/Authenticator.h" #include "../WorldStorage/SchematicFileSerializer.h" #include "../CompositeChat.h" @@ -2156,6 +2157,63 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L) +static int tolua_cClientHandle_GetUUIDsFromPlayerNames(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cClientHandle") || + !S.CheckParamTable(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Convert the input table into AStringVector: + AStringVector PlayerNames; + int NumNames = luaL_getn(L, 2); + PlayerNames.reserve(NumNames); + for (int i = 1; i <= NumNames; i++) + { + lua_rawgeti(L, 2, i); + AString Name; + S.GetStackValue(3, Name); + if (!Name.empty()) + { + PlayerNames.push_back(Name); + } + lua_pop(L, 1); + } + + // Push the output table onto the stack: + lua_newtable(L); // stack index 3 + + // Get the UUIDs: + AStringVector UUIDs = cRoot::Get()->GetAuthenticator().GetUUIDsFromPlayerNames(PlayerNames); + if (UUIDs.size() != PlayerNames.size()) + { + // A hard error has occured while processing the request, no UUIDs were returned. Return an empty table: + return 1; + } + + // Convert to output table, PlayerName -> UUID: + for (int i = 0; i < NumNames; i++) + { + if (UUIDs[i].empty()) + { + // No UUID was provided for PlayerName[i], skip it in the resulting table + continue; + } + lua_pushlstring(L, UUIDs[i].c_str(), UUIDs[i].length()); + lua_setfield(L, 3, PlayerNames[i].c_str()); + } + return 1; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -3083,9 +3141,10 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cClientHandle"); - tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); - tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); - tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); + tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); + tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); + tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cClientHandle_GetUUIDsFromPlayerNames); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); From b6677efecdd026a7eb8d652a067e4770182cd7c1 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 28 Jul 2014 17:14:23 +0200 Subject: [PATCH 014/751] Debuggers: Added an example for cClientHandle:GetUUIDsFromPlayerNames(). --- MCServer/Plugins/Debuggers/Debuggers.lua | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index b402c1867..80416acc7 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -80,6 +80,7 @@ function Initialize(Plugin) TestBlockAreasString() TestStringBase64() + TestUUIDFromName() --[[ -- Test cCompositeChat usage in console-logging: @@ -275,6 +276,36 @@ end +function TestUUIDFromName() + LOG("Testing UUID-from-Name resolution...") + + -- Test by querying a few existing names, along with a non-existent one: + local PlayerNames = + { + "xoft", + "aloe_vera", + "nonexistent_player", + } + -- WARNING: Blocking operation! DO NOT USE IN TICK THREAD! + local UUIDs = cClientHandle:GetUUIDsFromPlayerNames(PlayerNames) + + -- Log the results: + for _, name in ipairs(PlayerNames) do + local UUID = UUIDs[name] + if (UUID == nil) then + LOG(" UUID(" .. name .. ") not found.") + else + LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"") + end + end + + LOG("UUID-from-Name resolution test finished.") +end + + + + + function TestSQLiteBindings() LOG("Testing SQLite bindings..."); From 036a8ff98e890071089e9938cb87c5c4323152f0 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 28 Jul 2014 19:59:53 +0200 Subject: [PATCH 015/751] Added SQLiteCpp library. This provides C++ wrappers for SQLite, making it safer to use in the C++ environment. --- .gitmodules | 3 +++ CMakeLists.txt | 9 +++++++++ Install/SQLiteCpp-LICENSE.txt | 20 ++++++++++++++++++++ Install/Zip2008.list | 1 + lib/SQLiteCpp | 1 + 5 files changed, 34 insertions(+) create mode 100644 Install/SQLiteCpp-LICENSE.txt create mode 160000 lib/SQLiteCpp diff --git a/.gitmodules b/.gitmodules index 2aaee3624..8e63ee0a9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "lib/polarssl"] path = lib/polarssl url = https://github.com/mc-server/polarssl +[submodule "lib/SQLiteCpp"] + path = lib/SQLiteCpp + url = https://github.com/mc-server/SQLiteCpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a6400c1b4..478b79047 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,14 @@ endif() project (MCServer) +# Set options for SQLiteCpp, disable all their tests and lints: +set(SQLITECPP_RUN_CPPLINT OFF CACHE BOOL "Run cpplint.py tool for Google C++ StyleGuide." FORCE) +set(SQLITECPP_RUN_CPPCHECK OFF CACHE BOOL "Run cppcheck C++ static analysis tool." FORCE) +set(SQLITECPP_RUN_DOXYGEN OFF CACHE BOOL "Run Doxygen C++ documentation tool." FORCE) +set(SQLITECPP_BUILD_EXAMPLES OFF CACHE BOOL "Build examples." FORCE) +set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." FORCE) +set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "Add the internal SQLite3 source to the project." FORCE) + # Include all the libraries: add_subdirectory(lib/inifile/) add_subdirectory(lib/jsoncpp/) @@ -60,6 +68,7 @@ add_subdirectory(lib/zlib/) add_subdirectory(lib/lua/) add_subdirectory(lib/tolua++/) add_subdirectory(lib/sqlite/) +add_subdirectory(lib/SQLiteCpp/) add_subdirectory(lib/expat/) add_subdirectory(lib/luaexpat/) diff --git a/Install/SQLiteCpp-LICENSE.txt b/Install/SQLiteCpp-LICENSE.txt new file mode 100644 index 000000000..ec952abba --- /dev/null +++ b/Install/SQLiteCpp-LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2012-2014 Sebastien Rombauts (sebastien.rombauts@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Install/Zip2008.list b/Install/Zip2008.list index b118ccbf9..5736867d8 100644 --- a/Install/Zip2008.list +++ b/Install/Zip2008.list @@ -11,4 +11,5 @@ MCServer*debug.cmd Lua-LICENSE.txt LuaExpat-license.html LuaSQLite3-LICENSE.txt +SQLiteCpp-LICENSE.txt MersenneTwister-LICENSE.txt diff --git a/lib/SQLiteCpp b/lib/SQLiteCpp new file mode 160000 index 000000000..27b9d1118 --- /dev/null +++ b/lib/SQLiteCpp @@ -0,0 +1 @@ +Subproject commit 27b9d111818af3b05bcf4153bb6e380fe1dd6816 From 5fb5f6671f2b138dc56187183f0650b70a4d2eb4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 28 Jul 2014 20:16:24 +0200 Subject: [PATCH 016/751] Fixed include directories for SQLiteCpp. --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 478b79047..2b30e1e0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,12 @@ add_subdirectory(lib/SQLiteCpp/) add_subdirectory(lib/expat/) add_subdirectory(lib/luaexpat/) +# Add proper include directories so that SQLiteCpp can find SQLite3: +get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES) +set(SQLITECPP_INCLUDES "${SQLITECPP_INCLUDES}" "${CMAKE_CURRENT_SOURCE_DIR}/lib/sqlite/") +message("SQLiteCpp includes: " "${SQLITECPP_INCLUDES}") +set_property(DIRECTORY lib/SQLiteCpp/ PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}") + if (WIN32) add_subdirectory(lib/luaproxy/) endif() From 7f7604a186885107d0bd9625d969aef45a60dcce Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 28 Jul 2014 22:06:47 +0200 Subject: [PATCH 017/751] Fixed SQLiteCpp include paths for MSVC2010+. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b30e1e0b..dd9b1e67c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,8 +75,8 @@ add_subdirectory(lib/luaexpat/) # Add proper include directories so that SQLiteCpp can find SQLite3: get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES) set(SQLITECPP_INCLUDES "${SQLITECPP_INCLUDES}" "${CMAKE_CURRENT_SOURCE_DIR}/lib/sqlite/") -message("SQLiteCpp includes: " "${SQLITECPP_INCLUDES}") set_property(DIRECTORY lib/SQLiteCpp/ PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}") +set_property(TARGET SQLiteCpp PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}") if (WIN32) add_subdirectory(lib/luaproxy/) From adae2b70b1733a280fe342ca6d0dca7e37301f4f Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Tue, 29 Jul 2014 22:31:31 +0200 Subject: [PATCH 018/751] Added cBlockInfo::CanBeTerraformed and made finishers use it I might have forgotten some of them though --- src/BlockInfo.cpp | 21 +++++++++++++++++++++ src/BlockInfo.h | 4 ++++ src/Generating/Caves.cpp | 24 ++---------------------- src/Generating/RoughRavines.cpp | 26 ++++---------------------- 4 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 602deb26d..311a53c42 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -17,6 +17,7 @@ cBlockInfo::cBlockInfo() , m_IsSnowable(false) , m_IsSolid(true) , m_FullyOccupiesVoxel(false) + , m_CanBeTerraformed(false) , m_Handler(NULL) {} @@ -548,6 +549,26 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_STONE ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_STONE_BRICKS ].m_FullyOccupiesVoxel = true; a_Info[E_BLOCK_WOOL ].m_FullyOccupiesVoxel = true; + + + // Blocks that can be terraformed + a_Info[E_BLOCK_COAL_ORE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_COBBLESTONE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_DIAMOND_ORE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_DIRT ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_GOLD_ORE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_GRASS ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_GRAVEL ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_HARDENED_CLAY ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_IRON_ORE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_MYCELIUM ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_NETHERRACK ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_REDSTONE_ORE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_CanBeTerraformed = true; + a_Info[E_BLOCK_SAND ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_SANDSTONE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_STAINED_CLAY ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_STONE ].m_CanBeTerraformed = true; } diff --git a/src/BlockInfo.h b/src/BlockInfo.h index e6ce566c5..4c66c095a 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -45,6 +45,9 @@ public: /** Does this block fully occupy its voxel - is it a 'full' block? */ bool m_FullyOccupiesVoxel; + /** Can a finisher change it? */ + bool m_CanBeTerraformed; + // tolua_end /** Associated block handler. */ @@ -60,6 +63,7 @@ public: inline static bool IsSnowable (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSnowable; } inline static bool IsSolid (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSolid; } inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; } + inline static bool CanBeTerraformed (BLOCKTYPE a_Type) { return Get(a_Type).m_CanBeTerraformed; } // tolua_end diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 3b71efb57..6fc371958 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -497,29 +497,9 @@ void cCaveTunnel::ProcessChunk( int SqDist = (DifX - x) * (DifX - x) + (DifY - y) * (DifY - y) + (DifZ - z) * (DifZ - z); if (4 * SqDist <= SqRad) { - switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z)) + if (cBlockInfo::CanBeTerraformed(cChunkDef::GetBlock(a_BlockTypes, x, y, z))) { - // Only carve out these specific block types - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_STONE: - case E_BLOCK_COBBLESTONE: - case E_BLOCK_GRAVEL: - case E_BLOCK_SAND: - case E_BLOCK_SANDSTONE: - case E_BLOCK_SOULSAND: - case E_BLOCK_NETHERRACK: - case E_BLOCK_COAL_ORE: - case E_BLOCK_IRON_ORE: - case E_BLOCK_GOLD_ORE: - case E_BLOCK_DIAMOND_ORE: - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); - break; - } - default: break; + cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); } } } // for y diff --git a/src/Generating/RoughRavines.cpp b/src/Generating/RoughRavines.cpp index badc7768e..2ee3704b3 100644 --- a/src/Generating/RoughRavines.cpp +++ b/src/Generating/RoughRavines.cpp @@ -201,29 +201,11 @@ protected: { continue; } - switch (a_ChunkDesc.GetBlockType(x, y, z)) + + if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z))) { - // Only carve out these specific block types - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_STONE: - case E_BLOCK_COBBLESTONE: - case E_BLOCK_GRAVEL: - case E_BLOCK_SAND: - case E_BLOCK_SANDSTONE: - case E_BLOCK_NETHERRACK: - case E_BLOCK_COAL_ORE: - case E_BLOCK_IRON_ORE: - case E_BLOCK_GOLD_ORE: - case E_BLOCK_DIAMOND_ORE: - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); - break; - } - default: break; - } // switch (BlockType) + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); + } } // for y } // for x, z - a_BlockTypes } // for itr - m_Points[] From 931443ac67cefade2ebd0d29fd65a49d22293ea2 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Tue, 29 Jul 2014 22:40:40 +0200 Subject: [PATCH 019/751] Added soulsand to the terraformed list. --- src/BlockInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 311a53c42..4bc3fbbdc 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -567,6 +567,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_CanBeTerraformed = true; a_Info[E_BLOCK_SAND ].m_CanBeTerraformed = true; a_Info[E_BLOCK_SANDSTONE ].m_CanBeTerraformed = true; + a_Info[E_BLOCK_SOULSAND ].m_CanBeTerraformed = true; a_Info[E_BLOCK_STAINED_CLAY ].m_CanBeTerraformed = true; a_Info[E_BLOCK_STONE ].m_CanBeTerraformed = true; } From 9a4d80fc3b9dbaa09c8e6d9e8021762a486f280f Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 00:45:03 +0200 Subject: [PATCH 020/751] Fixed compile error with clang. --- src/Generating/FinishGen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index ed32768b3..cf84a0336 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -163,7 +163,7 @@ public: m_Amount(a_Amount) { // Initialize all the block types. - for (int idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) + for (size_t idx = 0; idx < (size_t)ARRAYCOUNT(m_IsAllowedBelow); ++idx) { m_IsAllowedBelow[idx] = false; } @@ -175,7 +175,7 @@ public: } // Initialize all the biome types. - for (int idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) + for (size_t idx = 0; idx < (size_t)ARRAYCOUNT(m_IsBiomeAllowed); ++idx) { m_IsBiomeAllowed[idx] = false; } From 438e4088d6a38f9904a36f2e1a358965d9fb4a26 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 01:22:51 +0200 Subject: [PATCH 021/751] Changed size_t to 'unsigned long' --- src/Generating/FinishGen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index cf84a0336..7171036e2 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -163,7 +163,7 @@ public: m_Amount(a_Amount) { // Initialize all the block types. - for (size_t idx = 0; idx < (size_t)ARRAYCOUNT(m_IsAllowedBelow); ++idx) + for (unsigned long idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) { m_IsAllowedBelow[idx] = false; } @@ -175,7 +175,7 @@ public: } // Initialize all the biome types. - for (size_t idx = 0; idx < (size_t)ARRAYCOUNT(m_IsBiomeAllowed); ++idx) + for (unsigned long idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) { m_IsBiomeAllowed[idx] = false; } From 487c57242964ef4a86fc4f41c1c538d9df9ec892 Mon Sep 17 00:00:00 2001 From: archshift Date: Tue, 29 Jul 2014 19:14:56 -0700 Subject: [PATCH 022/751] Entity.h: Moved constants out of some unnamed enum --- src/Entities/Entity.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index e66194ca2..b9c280b6b 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -128,20 +128,20 @@ public: esFireworkExploding = 17, } ; - enum - { - FIRE_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in fire - FIRE_DAMAGE = 1, ///< How much damage to deal when standing in fire - LAVA_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in lava - LAVA_DAMAGE = 5, ///< How much damage to deal when standing in lava - BURN_TICKS_PER_DAMAGE = 20, ///< How many ticks to wait between damaging an entity when it is burning - BURN_DAMAGE = 1, ///< How much damage to deal when the entity is burning - BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire - MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have - DROWNING_TICKS = 20, ///< Number of ticks per heart of damage - VOID_BOUNDARY = -46, ///< At what position Y to begin applying void damage - FALL_DAMAGE_HEIGHT = 4 ///< At what position Y fall damage is applied - } ; + static const int FIRE_TICKS_PER_DAMAGE = 10; ///< Ticks to wait between damaging an entity when it stands in fire + static const int FIRE_DAMAGE = 1; ///< Damage to deal when standing in fire + static const int LAVA_TICKS_PER_DAMAGE = 10; ///< Ticks to wait between damaging an entity when it stands in lava + static const int LAVA_DAMAGE = 5; ///< Damage to deal when standing in lava + static const int BURN_TICKS_PER_DAMAGE = 20; ///< Ticks to wait between damaging an entity when it is burning + static const int BURN_DAMAGE = 1; ///< Damage to deal when the entity is burning + + static const int BURN_TICKS = 200; ///< Ticks to keep an entity burning after it has stood in lava / fire + + static const int MAX_AIR_LEVEL = 300; ///< Maximum air an entity can have + static const int DROWNING_TICKS = 20; ///< Number of ticks per heart of damage + + static const int VOID_BOUNDARY = -46; ///< Y position to begin applying void damage + static const int FALL_DAMAGE_HEIGHT = 4; ///< Y difference after which fall damage is applied cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); virtual ~cEntity(); From 7022ae79886a9f90f30ff54387702d406b723837 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 07:08:29 +0200 Subject: [PATCH 023/751] Fixed FinishGen.h types. --- src/Generating/FinishGen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index 7171036e2..50a0fd2e7 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -163,7 +163,7 @@ public: m_Amount(a_Amount) { // Initialize all the block types. - for (unsigned long idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) + for (size_t idx = 0; idx < ARRAYCOUNT(m_IsAllowedBelow); ++idx) { m_IsAllowedBelow[idx] = false; } @@ -175,7 +175,7 @@ public: } // Initialize all the biome types. - for (unsigned long idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) + for (size_t idx = 0; idx < ARRAYCOUNT(m_IsBiomeAllowed); ++idx) { m_IsBiomeAllowed[idx] = false; } From 1d684697186de4340c6a1cc5aea6a14ffd19c002 Mon Sep 17 00:00:00 2001 From: archshift Date: Tue, 29 Jul 2014 22:43:25 -0700 Subject: [PATCH 024/751] Fixed "Dependency" typos --- .gitignore | 2 +- src/Bindings/CMakeLists.txt | 4 ++-- src/CMakeLists.txt | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 51987336c..a4cbef72f 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,7 @@ install_mainfest.txt src/MCServer lib/tolua++/tolua src/Bindings/Bindings.* -src/Bindings/BindingDependecies.txt +src/Bindings/BindingDependencies.txt MCServer.dir/ src/AllFiles.lst diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 2ea2fa8c0..48e7ce79c 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -125,8 +125,8 @@ if (NOT MSVC) DEPENDS ${BINDING_DEPENDENCIES} ) endif () -set_source_files_properties(Bindings/Bindings.cpp PROPERTIES GENERATED TRUE) -set_source_files_properties(Bindings/Bindings.h PROPERTIES GENERATED TRUE) +set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES GENERATED TRUE) +set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.h PROPERTIES GENERATED TRUE) if(NOT MSVC) add_library(Bindings ${SRCS} ${HDRS}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 29337cb2e..87599c60d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,10 +151,10 @@ if (NOT MSVC) get_directory_property(BINDING_DEPENDENCIES DIRECTORY "Bindings" DEFINITION BINDING_DEPENDENCIES) #clear file - file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependecies.txt) - foreach(dependecy ${BINDING_DEPENDECIES}) - #write each dependecy on a seperate line - file(APPEND ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependecies.txt "${dependecy}\n") + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependencies.txt) + foreach(dependency ${BINDING_DEPENDENCIES}) + #write each dependency on a seperate line + file(APPEND ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependencies.txt "${dependency}\n") endforeach() set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "Bindings.cpp Bindings.h") From 75b7c3775528ced647eb5d7db3437d2856e01e7e Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 13:06:48 +0200 Subject: [PATCH 025/751] PreSimulator: Added configurations. You can now choose if it should pregenerate something or not --- src/Generating/ComposableGenerator.cpp | 7 ++++++- src/Generating/FinishGen.cpp | 22 ++++++++++++++++++---- src/Generating/FinishGen.h | 7 ++++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index a7659149a..cedb9aeb7 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -408,7 +408,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { - m_FinishGens.push_back(new cFinishGenPreSimulator); + // Load the settings + bool PreSimulateFallingBlocks = a_IniFile.GetValueSetB("Generator", "PreSimulatorFallingBlocks", true); + bool PreSimulateWater = a_IniFile.GetValueSetB("Generator", "PreSimulatorWater", true); + bool PreSimulateLava = a_IniFile.GetValueSetB("Generator", "PreSimulatorLava", true); + + m_FinishGens.push_back(new cFinishGenPreSimulator(PreSimulateFallingBlocks, PreSimulateWater, PreSimulateLava)); } else if (NoCaseCompare(*itr, "RainbowRoads") == 0) { diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index f53addb68..e8324095e 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -555,7 +555,10 @@ void cFinishGenBottomLava::GenFinish(cChunkDesc & a_ChunkDesc) //////////////////////////////////////////////////////////////////////////////// // cFinishGenPreSimulator: -cFinishGenPreSimulator::cFinishGenPreSimulator(void) +cFinishGenPreSimulator::cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava) : + m_PreSimulateFallingBlocks(a_PreSimulateFallingBlocks), + m_PreSimulateWater(a_PreSimulateWater), + m_PreSimulateLava(a_PreSimulateLava) { // Nothing needed yet } @@ -566,9 +569,20 @@ cFinishGenPreSimulator::cFinishGenPreSimulator(void) void cFinishGenPreSimulator::GenFinish(cChunkDesc & a_ChunkDesc) { - CollapseSandGravel(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); - StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + if (m_PreSimulateFallingBlocks) + { + CollapseSandGravel(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); + } + + if (m_PreSimulateWater) + { + StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER); + } + + if (m_PreSimulateLava) + { + StationarizeFluid(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap(), E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA); + } // TODO: other operations } diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index 50a0fd2e7..4a08d70c8 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -240,9 +240,14 @@ class cFinishGenPreSimulator : public cFinishGen { public: - cFinishGenPreSimulator(void); + cFinishGenPreSimulator(bool a_PreSimulateFallingBlocks, bool a_PreSimulateWater, bool a_PreSimulateLava); protected: + + bool m_PreSimulateFallingBlocks; + bool m_PreSimulateWater; + bool m_PreSimulateLava; + // Drops hanging sand and gravel down to the ground, recalculates heightmap void CollapseSandGravel( cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change From 4dd858f8997488e2252f5a04df9df1654a70d67f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 29 Jul 2014 17:45:55 +0200 Subject: [PATCH 026/751] Added a cMojangAPI class for PlayerName -> UUID lookups, with cache. The cache is persisted into a SQLite DB file on server shutdown. --- src/Bindings/ManualBindings.cpp | 2 +- src/CMakeLists.txt | 4 +- src/Protocol/Authenticator.cpp | 216 +--------------- src/Protocol/Authenticator.h | 27 +- src/Protocol/CMakeLists.txt | 2 + src/Protocol/MojangAPI.cpp | 446 ++++++++++++++++++++++++++++++++ src/Protocol/MojangAPI.h | 102 ++++++++ src/Root.cpp | 1 + src/Root.h | 3 + 9 files changed, 564 insertions(+), 239 deletions(-) create mode 100644 src/Protocol/MojangAPI.cpp create mode 100644 src/Protocol/MojangAPI.h diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 28ee00b36..6d69e2595 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2189,7 +2189,7 @@ static int tolua_cClientHandle_GetUUIDsFromPlayerNames(lua_State * L) lua_newtable(L); // stack index 3 // Get the UUIDs: - AStringVector UUIDs = cRoot::Get()->GetAuthenticator().GetUUIDsFromPlayerNames(PlayerNames); + AStringVector UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames); if (UUIDs.size() != PlayerNames.size()) { // A hard error has occured while processing the request, no UUIDs were returned. Return an empty table: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 29337cb2e..1d1c33088 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -138,6 +138,8 @@ SET (HDRS XMLParser.h) include_directories(".") +include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/sqlite") +include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../lib/SQLiteCpp/include") if (NOT MSVC) # Bindings need to reference other folders, so they are done here instead @@ -311,4 +313,4 @@ endif () if (WIN32) target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) endif() -target_link_libraries(${EXECUTABLE} luaexpat iniFile jsoncpp polarssl zlib sqlite lua) +target_link_libraries(${EXECUTABLE} luaexpat iniFile jsoncpp polarssl zlib sqlite lua SQLiteCpp) diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 75721589f..e5d16cf10 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Authenticator.h" +#include "MojangAPI.h" #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" @@ -17,76 +18,11 @@ #define DEFAULT_AUTH_SERVER "sessionserver.mojang.com" #define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%" -#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com" -#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft" - -/** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: -Downloaded from http://certs.starfieldtech.com/repository/ */ -static const AString StarfieldCACert() -{ - return AString( - // G2 cert - "-----BEGIN CERTIFICATE-----\n" - "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n" - "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" - "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n" - "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n" - "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n" - "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n" - "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n" - "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" - "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n" - "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n" - "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n" - "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n" - "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n" - "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n" - "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n" - "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n" - "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n" - "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n" - "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n" - "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n" - "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" - "-----END CERTIFICATE-----\n\n" - // Original (G1) cert: - "-----BEGIN CERTIFICATE-----\n" - "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n" - "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n" - "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n" - "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n" - "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n" - "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n" - "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n" - "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n" - "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n" - "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n" - "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n" - "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n" - "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n" - "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n" - "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n" - "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n" - "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n" - "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n" - "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n" - "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n" - "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n" - "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n" - "-----END CERTIFICATE-----\n" - ); -} - - - - cAuthenticator::cAuthenticator(void) : super("cAuthenticator"), m_Server(DEFAULT_AUTH_SERVER), m_Address(DEFAULT_AUTH_ADDRESS), - m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER), - m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), m_ShouldAuthenticate(true) { } @@ -109,8 +45,6 @@ void cAuthenticator::ReadINI(cIniFile & IniFile) m_Server = IniFile.GetValueSet ("Authentication", "Server", DEFAULT_AUTH_SERVER); m_Address = IniFile.GetValueSet ("Authentication", "Address", DEFAULT_AUTH_ADDRESS); m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); - m_NameToUUIDServer = IniFile.GetValueSet ("Authentication", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); - m_NameToUUIDAddress = IniFile.GetValueSet ("Authentication", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); } @@ -157,93 +91,6 @@ void cAuthenticator::Stop(void) -AStringVector cAuthenticator::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames) -{ - AStringVector res; - - // Create the request body - a JSON containing all the playernames: - Json::Value root; - for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) - { - Json::Value req(*itr); - root.append(req); - } // for itr - a_PlayerNames[] - Json::FastWriter Writer; - AString RequestBody = Writer.write(root); - - // Create the HTTP request: - AString Request; - Request += "POST " + m_NameToUUIDAddress + " HTTP/1.1\r\n"; - Request += "Host: " + m_NameToUUIDServer + "\r\n"; - Request += "User-Agent: MCServer\r\n"; - Request += "Connection: close\r\n"; - Request += "Content-Type: application/json\r\n"; - Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); - Request += "\r\n"; - Request += RequestBody; - - // Get the response from the server: - AString Response; - if (!SecureGetFromAddress(StarfieldCACert(), m_NameToUUIDServer, Request, Response)) - { - return res; - } - - // Check the HTTP status line: - const AString Prefix("HTTP/1.1 200 OK"); - AString HexDump; - if (Response.compare(0, Prefix.size(), Prefix)) - { - LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); - LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); - return res; - } - - // Erase the HTTP headers from the response: - size_t idxHeadersEnd = Response.find("\r\n\r\n"); - if (idxHeadersEnd == AString::npos) - { - LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); - LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); - return res; - } - Response.erase(0, idxHeadersEnd + 4); - - // Parse the returned string into Json: - Json::Reader reader; - if (!reader.parse(Response, root, false) || !root.isArray()) - { - LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); - LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); - return res; - } - - // Fill in the resulting array; do not expect to get the UUIDs in the same order as the inputs: - size_t len = a_PlayerNames.size(); - size_t JsonCount = root.size(); - res.resize(len); - for (size_t idx = 0; idx < len; idx++) // For each input username... - { - const AString & InputName = a_PlayerNames[idx]; - for (size_t IdxJson = 0; IdxJson < JsonCount; ++IdxJson) - { - Json::Value & Val = root[IdxJson]; - AString JsonName = Val.get("name", "").asString(); - if (NoCaseCompare(JsonName, InputName) == 0) - { - res[idx] = Val.get("id", "").asString(); - break; - } - } // for IdxJson - root[] - } // for idx - a_PlayerNames[] / res[] - - return res; -} - - - - - void cAuthenticator::Execute(void) { for (;;) @@ -286,62 +133,6 @@ void cAuthenticator::Execute(void) -bool cAuthenticator::SecureGetFromAddress(const AString & a_CACerts, const AString & a_ExpectedPeerName, const AString & a_Data, AString & a_Response) -{ - // Connect the socket: - cBlockingSslClientSocket Socket; - Socket.SetTrustedRootCertsFromString(a_CACerts, a_ExpectedPeerName); - if (!Socket.Connect(a_ExpectedPeerName, 443)) - { - LOGWARNING("cAuthenticator: Can't connect to %s: %s", a_ExpectedPeerName.c_str(), Socket.GetLastErrorText().c_str()); - return false; - } - - if (!Socket.Send(a_Data.c_str(), a_Data.size())) - { - LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str()); - return false; - } - - // Read the HTTP response: - int ret; - unsigned char buf[1024]; - - for (;;) - { - ret = Socket.Receive(buf, sizeof(buf)); - - if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE)) - { - // This value should never be returned, it is handled internally by cBlockingSslClientSocket - LOGWARNING("cAuthenticator: SSL reading failed internally"); - return false; - } - if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) - { - break; - } - if (ret < 0) - { - LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret); - return false; - } - if (ret == 0) - { - break; - } - - a_Response.append((const char *)buf, (size_t)ret); - } - - Socket.Disconnect(); - return true; -} - - - - - bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties) { LOGD("Trying to authenticate user %s", a_UserName.c_str()); @@ -359,7 +150,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S Request += "\r\n"; AString Response; - if (!SecureGetFromAddress(StarfieldCACert(), m_Server, Request, Response)) + if (!cMojangAPI::SecureRequest(m_Server, Request, Response)) { return false; } @@ -399,6 +190,9 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S a_UserName = root.get("name", "Unknown").asString(); a_UUID = root.get("id", "").asString(); a_Properties = root["properties"]; + + // Store the player's UUID in the NameToUUID map in MojangAPI: + cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(a_UserName, a_UUID); // If the UUID doesn't contain the dashes, insert them at the proper places: if (a_UUID.size() == 32) diff --git a/src/Protocol/Authenticator.h b/src/Protocol/Authenticator.h index 82ecb1f7a..853eff535 100644 --- a/src/Protocol/Authenticator.h +++ b/src/Protocol/Authenticator.h @@ -11,8 +11,6 @@ #pragma once -#ifndef CAUTHENTICATOR_H_INCLUDED -#define CAUTHENTICATOR_H_INCLUDED #include "../OSSupport/IsThread.h" @@ -53,12 +51,6 @@ public: /** Stops the authenticator thread. The thread may be started and stopped repeatedly */ void Stop(void); - /** Converts the player names into UUIDs. - a_PlayerName[idx] will be converted to UUID and returned as idx-th value - The UUID will be empty on error. - Blocking operation, do not use in world-tick thread! */ - AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName); - private: class cUser @@ -91,34 +83,17 @@ private: For example "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%". */ AString m_Address; - /** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */ - AString m_NameToUUIDServer; - - /** The URL to use for converting player names to UUIDs, without server part. - For example "/profiles/page/1". */ - AString m_NameToUUIDAddress; - AString m_PropertiesAddress; bool m_ShouldAuthenticate; /** cIsThread override: */ virtual void Execute(void) override; - /** Connects to a hostname using SSL, sends given data, and sets the response, returning whether all was successful or not */ - bool SecureGetFromAddress(const AString & a_CACerts, const AString & a_ExpectedPeerName, const AString & a_Request, AString & a_Response); - /** Returns true if the user authenticated okay, false on error - Sets the username, UUID, and properties (i.e. skin) fields - */ + Returns the case-corrected username, UUID, and properties (eg. skin). */ bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties); }; - -#endif // CAUTHENTICATOR_H_INCLUDED - - - - diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index ae447ce54..1ba66ff1f 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") SET (SRCS Authenticator.cpp ChunkDataSerializer.cpp + MojangAPI.cpp Protocol125.cpp Protocol132.cpp Protocol14x.cpp @@ -18,6 +19,7 @@ SET (SRCS SET (HDRS Authenticator.h ChunkDataSerializer.h + MojangAPI.h Protocol.h Protocol125.h Protocol132.h diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp new file mode 100644 index 000000000..05f9c09a7 --- /dev/null +++ b/src/Protocol/MojangAPI.cpp @@ -0,0 +1,446 @@ + +// MojangAPI.cpp + +// Implements the cMojangAPI class representing the various API points provided by Mojang's webservices, and a cache for their results + +#include "Globals.h" +#include "MojangAPI.h" +#include "SQLiteCpp/Database.h" +#include "SQLiteCpp/Statement.h" +#include "inifile/iniFile.h" +#include "json/json.h" +#include "PolarSSL++/BlockingSslClientSocket.h" + + + + + +/** The maximum age for items to be kept in the cache. Any item older than this will be removed. */ +const Int64 MAX_AGE = 7 * 24 * 60 * 60; // 7 days ago + + + + + +#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com" +#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft" + + + + + +/** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: +Downloaded from http://certs.starfieldtech.com/repository/ */ +static const AString & StarfieldCACert(void) +{ + static const AString Cert( + // G2 cert + "-----BEGIN CERTIFICATE-----\n" + "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n" + "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" + "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n" + "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n" + "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n" + "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n" + "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n" + "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n" + "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n" + "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n" + "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n" + "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n" + "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n" + "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n" + "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n" + "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n" + "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n" + "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n" + "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n" + "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" + "-----END CERTIFICATE-----\n\n" + // Original (G1) cert: + "-----BEGIN CERTIFICATE-----\n" + "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n" + "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n" + "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n" + "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n" + "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n" + "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n" + "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n" + "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n" + "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n" + "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n" + "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n" + "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n" + "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n" + "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n" + "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n" + "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n" + "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n" + "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n" + "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n" + "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n" + "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n" + "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n" + "-----END CERTIFICATE-----\n" + ); + + return Cert; +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cMojangAPI: + +cMojangAPI::cMojangAPI(void) : + m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER), + m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS) +{ +} + + + + + +cMojangAPI::~cMojangAPI() +{ + SaveCachesToDisk(); +} + + + + + +void cMojangAPI::Start(cIniFile & a_SettingsIni) +{ + m_NameToUUIDServer = a_SettingsIni.GetValueSet("Authentication", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); + m_NameToUUIDAddress = a_SettingsIni.GetValueSet("Authentication", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); + LoadCachesFromDisk(); +} + + + + + +AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames) +{ + // Convert all playernames to lowercase: + AStringVector PlayerNames; + for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) + { + AString Lower(*itr); + PlayerNames.push_back(StrToLower(Lower)); + } // for itr - a_PlayerNames[] + + // Request the cache to populate any names not yet contained: + CacheNamesToUUIDs(PlayerNames); + + // Retrieve from cache: + size_t idx = 0; + AStringVector res; + res.resize(PlayerNames.size()); + cCSLock Lock(m_CSNameToUUID); + for (AStringVector::const_iterator itr = PlayerNames.begin(), end = PlayerNames.end(); itr != end; ++itr, ++idx) + { + cNameToUUIDMap::const_iterator itrN = m_NameToUUID.find(*itr); + if (itrN != m_NameToUUID.end()) + { + res[idx] = itrN->second.m_UUID; + } + } // for itr - PlayerNames[] + return res; +} + + + + + +void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) +{ + AString lcName(a_PlayerName); + Int64 Now = time(NULL); + cCSLock Lock(m_CSNameToUUID); + m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(a_PlayerName, a_UUID, Now); +} + + + + + +bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response) +{ + // Connect the socket: + cBlockingSslClientSocket Socket; + Socket.SetTrustedRootCertsFromString(StarfieldCACert(), a_ServerName); + if (!Socket.Connect(a_ServerName, 443)) + { + LOGWARNING("%s: Can't connect to %s: %s", __FUNCTION__, a_ServerName.c_str(), Socket.GetLastErrorText().c_str()); + return false; + } + + if (!Socket.Send(a_Request.c_str(), a_Request.size())) + { + LOGWARNING("%s: Writing SSL data failed: %s", __FUNCTION__, Socket.GetLastErrorText().c_str()); + return false; + } + + // Read the HTTP response: + int ret; + unsigned char buf[1024]; + + for (;;) + { + ret = Socket.Receive(buf, sizeof(buf)); + + if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE)) + { + // This value should never be returned, it is handled internally by cBlockingSslClientSocket + LOGWARNING("%s: SSL reading failed internally", __FUNCTION__); + return false; + } + if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) + { + break; + } + if (ret < 0) + { + LOGWARNING("%s: SSL reading failed: -0x%x", __FUNCTION__, -ret); + return false; + } + if (ret == 0) + { + break; + } + + a_Response.append((const char *)buf, (size_t)ret); + } + + Socket.Disconnect(); + return true; +} + + + + + +AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) +{ + switch (a_UUID.size()) + { + case 32: return a_UUID; + + case 36: + { + AString res; + // TODO + return res; + } + } + LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str()); + return ""; +} + + + + + +AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) +{ + switch (a_UUID.size()) + { + case 36: return a_UUID; + + case 32: + { + AString res; + // TODO + return res; + } + } + LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str()); + return ""; +} + + + + + +void cMojangAPI::LoadCachesFromDisk(void) +{ + try + { + // Open up the SQLite DB: + SQLite::Database db("NameToUUID.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); + + // Clean up old entries: + { + SQLite::Statement stmt(db, "DELETE FROM PlayerNameToUUID WHERE DateTime < ?"); + Int64 LimitDateTime = time(NULL) - MAX_AGE; + stmt.bind(1, LimitDateTime); + stmt.exec(); + } + + // Retrieve all remaining entries:: + SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); + while (stmt.executeStep()) + { + AString PlayerName = stmt.getColumn(0); + AString UUID = stmt.getColumn(1); + Int64 DateTime = stmt.getColumn(2); + AString lcPlayerName = PlayerName; + m_NameToUUID[StrToLower(lcPlayerName)] = sUUIDRecord(PlayerName, UUID, DateTime); + } + } + catch (const SQLite::Exception & ex) + { + LOGINFO("Loading MojangAPI cache failed: %s", ex.what()); + } +} + + + + + +void cMojangAPI::SaveCachesToDisk(void) +{ + try + { + // Open up the SQLite DB: + SQLite::Database db("NameToUUID.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); + + // Remove all entries: + db.exec("DELETE FROM PlayerNameToUUID"); + + // Save all cache entries: + SQLite::Statement stmt(db, "INSERT INTO PlayerNameToUUID(PlayerName, UUID, DateTime) VALUES (?, ?, ?)"); + Int64 LimitDateTime = time(NULL) - MAX_AGE; + cCSLock Lock(m_CSNameToUUID); + for (cNameToUUIDMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr) + { + if (itr->second.m_DateTime < LimitDateTime) + { + // This item is too old, do not save + continue; + } + stmt.bind(1, itr->second.m_PlayerName); + stmt.bind(2, itr->second.m_UUID); + stmt.bind(3, itr->second.m_DateTime); + stmt.exec(); + stmt.reset(); + } + } + catch (const SQLite::Exception & ex) + { + LOGINFO("Saving MojangAPI cache failed: %s", ex.what()); + } +} + + + + + +void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) +{ + // Create a list of names to query, by removing those that are already cached: + AStringVector NamesToQuery; + NamesToQuery.reserve(a_PlayerNames.size()); + { + cCSLock Lock(m_CSNameToUUID); + for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) + { + if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) + { + NamesToQuery.push_back(*itr); + } + } // for itr - a_PlayerNames[] + } // Lock(m_CSNameToUUID) + + while (!NamesToQuery.empty()) + { + // Create the request body - a JSON containing up to 100 playernames: + Json::Value root; + int Count = 0; + AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); + for (; (itr != end) && (Count < 100); ++itr, ++Count) + { + Json::Value req(*itr); + root.append(req); + } // for itr - a_PlayerNames[] + NamesToQuery.erase(NamesToQuery.begin(), itr); + Json::FastWriter Writer; + AString RequestBody = Writer.write(root); + + // Create the HTTP request: + AString Request; + Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; + Request += "Host: " + m_NameToUUIDServer + "\r\n"; + Request += "User-Agent: MCServer\r\n"; + Request += "Connection: close\r\n"; + Request += "Content-Type: application/json\r\n"; + Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); + Request += "\r\n"; + Request += RequestBody; + + // Get the response from the server: + AString Response; + if (!SecureRequest(m_NameToUUIDServer, Request, Response)) + { + continue; + } + + // Check the HTTP status line: + const AString Prefix("HTTP/1.1 200 OK"); + AString HexDump; + if (Response.compare(0, Prefix.size(), Prefix)) + { + LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + continue; + } + + // Erase the HTTP headers from the response: + size_t idxHeadersEnd = Response.find("\r\n\r\n"); + if (idxHeadersEnd == AString::npos) + { + LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + continue; + } + Response.erase(0, idxHeadersEnd + 4); + + // Parse the returned string into Json: + Json::Reader reader; + if (!reader.parse(Response, root, false) || !root.isArray()) + { + LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); + LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + continue; + } + + // Store the returned results into cache: + size_t JsonCount = root.size(); + Int64 Now = time(NULL); + cCSLock Lock(m_CSNameToUUID); + for (size_t idx = 0; idx < JsonCount; ++idx) + { + Json::Value & Val = root[idx]; + AString JsonName = Val.get("name", "").asString(); + AString JsonUUID = Val.get("id", "").asString(); + if (JsonUUID.empty()) + { + continue; + } + AString lcName = JsonName; + m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(JsonName, JsonUUID, Now); + } // for idx - root[] + } // while (!NamesToQuery.empty()) +} + + + + diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h new file mode 100644 index 000000000..789fdf818 --- /dev/null +++ b/src/Protocol/MojangAPI.h @@ -0,0 +1,102 @@ + +// MojangAPI.h + +// Declares the cMojangAPI class representing the various API points provided by Mojang's webservices, and a cache for their results + + + + + +#pragma once + +#include + + + + + +class cMojangAPI +{ +public: + cMojangAPI(void); + ~cMojangAPI(); + + /** Initializes the API; reads the settings from the specified ini file. + Loads cached results from disk. */ + void Start(cIniFile & a_SettingsIni); + + /** Connects to the specified server using SSL, sends the given request and receives the response. + Checks Mojang certificates using the hard-coded Starfield root CA certificate. + Returns true if all was successful, false on failure. */ + static bool SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response); + + /** Converts the given UUID to its short form (32 bytes, no dashes). + Logs a warning and returns empty string if not a UUID. */ + static AString MakeUUIDShort(const AString & a_UUID); + + /** Converts the given UUID to its dashed form (36 bytes, 4 dashes). + Logs a warning and returns empty string if not a UUID. */ + static AString MakeUUIDDashed(const AString & a_UUID); + + /** Converts the player names into UUIDs. + a_PlayerName[idx] will be converted to UUID and returned as idx-th value + The UUID will be empty on error. + Blocking operation, do not use in world-tick thread! */ + AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName); + + /** Called by the Authenticator to add a PlayerName -> UUID mapping that it has received from + authenticating a user. This adds the cache item and "refreshes" it if existing, adjusting its datetime + stamp to now. */ + void AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID); + +protected: + struct sUUIDRecord + { + AString m_PlayerName; // Case-correct playername + AString m_UUID; + Int64 m_DateTime; // UNIXtime of the UUID lookup + + sUUIDRecord(void) : + m_UUID(), + m_DateTime(time(NULL)) + { + } + + sUUIDRecord(const AString & a_PlayerName, const AString & a_UUID, Int64 a_DateTime) : + m_PlayerName(a_PlayerName), + m_UUID(a_UUID), + m_DateTime(a_DateTime) + { + } + }; + typedef std::map cNameToUUIDMap; // maps Lowercased PlayerName to sUUIDRecord + + /** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */ + AString m_NameToUUIDServer; + + /** The URL to use for converting player names to UUIDs, without server part. + For example "/profiles/page/1". */ + AString m_NameToUUIDAddress; + + /** Cache for the Name-to-UUID lookups. The map key is expected lowercased. Protected by m_CSNameToUUID. */ + cNameToUUIDMap m_NameToUUID; + + /** Protects m_NameToUUID against simultaneous multi-threaded access. */ + cCriticalSection m_CSNameToUUID; + + + /** Loads the caches from a disk storage. */ + void LoadCachesFromDisk(void); + + /** Saves the caches to a disk storage. */ + void SaveCachesToDisk(void); + + /** Makes sure all specified names are in the cache. Downloads any missing ones from Mojang API servers. + Names that are not valid are not added into the cache. + ASSUMEs that a_PlayerNames contains lowercased player names. */ + void CacheNamesToUUIDs(const AStringVector & a_PlayerNames); +} ; + + + + diff --git a/src/Root.cpp b/src/Root.cpp index b03a13382..7d4fb80fd 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -145,6 +145,7 @@ void cRoot::Start(void) } LOG("Starting server..."); + m_MojangAPI.Start(IniFile); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init if (!m_Server->InitServer(IniFile)) { LOGERROR("Failure starting server, aborting..."); diff --git a/src/Root.h b/src/Root.h index 08aafe3c9..92a60a10d 100644 --- a/src/Root.h +++ b/src/Root.h @@ -2,6 +2,7 @@ #pragma once #include "Protocol/Authenticator.h" +#include "Protocol/MojangAPI.h" #include "HTTPServer/HTTPServer.h" #include "Defines.h" @@ -78,6 +79,7 @@ public: cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } + cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } /** Queues a console command for execution through the cServer class. The command will be executed in the tick thread @@ -182,6 +184,7 @@ private: cWebAdmin * m_WebAdmin; cPluginManager * m_PluginManager; cAuthenticator m_Authenticator; + cMojangAPI m_MojangAPI; cHTTPServer m_HTTPServer; cMCLogger * m_Log; From 6476bd0e2ee7e128e3eaa56159f169f0a53736ff Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 13:44:03 +0200 Subject: [PATCH 027/751] Exported cMojangAPI to Lua. --- MCServer/Plugins/APIDump/APIDesc.lua | 27 ++++++++++++++++++++++++++- src/Bindings/AllToLua.pkg | 1 + src/Bindings/ManualBindings.cpp | 9 ++++++--- src/Protocol/MojangAPI.h | 13 ++++++++++++- src/Root.h | 2 +- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index f29c47338..e5114784e 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -529,7 +529,6 @@ end GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." }, GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" }, GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." }, - GetUUIDsFromPlayerNames = { Params = "PlayerNames", Return = "table", Notes = "(STATIC) Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. Queries the Mojang servers for the results. WARNING: Do NOT use this function while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely. NOTE: Mojang API has a limit of 100 names per query and 600 queries per 10 minutes (may change)" }, GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" }, GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" }, HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." }, @@ -1607,6 +1606,31 @@ a_Player:OpenWindow(Window); }, -- cMapManager + cMojangAPI = + { + Desc = [[ + Provides interface to various API functions that Mojang provides through their servers. Note that + some of these calls will wait for a response from the network, and so shouldn't be used while the + server is fully running (or at least when there are players connected) to avoid percepted lag.

+

+ Some functions are static and do not require an instance to be called. For others, you need to get + the singleton instance of this class using {{cRoot}}'s GetMojangAPI() function.

+

+ Mojang uses two formats for UUIDs, short and dashed. MCServer works with short UUIDs internally, but + will convert to dashed UUIDs where needed - in the protocol login for example. The MakeUUIDShort() + and MakeUUIDDashed() functions are provided for plugins to use for conversion between the two + formats. + ]], + Functions = + { + AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp." }, + GetUUIDsFromPlayerNames = { Params = "PlayerNames", Return = "table", Notes = "Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. Queries the Mojang servers for the results. WARNING: Do NOT use this function while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, + MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, + MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, + }, + + }, + cMonster = { Desc = [[ @@ -2002,6 +2026,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); 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." }, + GetMojangAPI = { Params = "", Return = "{{cMojangAPI}}", Notes = "Returns the {{cMojangAPI}} 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." }, diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 1e5dfd2fe..d3e3f5b45 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -77,6 +77,7 @@ $cfile "../Map.h" $cfile "../MapManager.h" $cfile "../Scoreboard.h" $cfile "../Statistics.h" +$cfile "../Protocol/MojangAPI.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 6d69e2595..026a6bad5 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2157,11 +2157,11 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L) -static int tolua_cClientHandle_GetUUIDsFromPlayerNames(lua_State * L) +static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) { cLuaState S(L); if ( - !S.CheckParamUserTable(1, "cClientHandle") || + !S.CheckParamUserTable(1, "cMojangAPI") || !S.CheckParamTable(2) || !S.CheckParamEnd(3) ) @@ -3144,9 +3144,12 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); - tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cClientHandle_GetUUIDsFromPlayerNames); tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cMojangAPI"); + tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cMojangAPI_GetUUIDsFromPlayerNames); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cItemGrid"); tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords); tolua_endmodule(tolua_S); diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 789fdf818..cc2902a19 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -15,9 +15,12 @@ +// tolua_begin class cMojangAPI { public: + // tolua_end + cMojangAPI(void); ~cMojangAPI(); @@ -30,6 +33,8 @@ 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 + /** Converts the given UUID to its short form (32 bytes, no dashes). Logs a warning and returns empty string if not a UUID. */ static AString MakeUUIDShort(const AString & a_UUID); @@ -38,16 +43,22 @@ public: Logs a warning and returns empty string if not a UUID. */ static AString MakeUUIDDashed(const AString & a_UUID); + // tolua_end + /** Converts the player names into UUIDs. a_PlayerName[idx] will be converted to UUID and returned as idx-th value The UUID will be empty on error. Blocking operation, do not use in world-tick thread! */ AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName); + // tolua_begin + /** Called by the Authenticator to add a PlayerName -> UUID mapping that it has received from authenticating a user. This adds the cache item and "refreshes" it if existing, adjusting its datetime stamp to now. */ void AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID); + + // tolua_end protected: struct sUUIDRecord @@ -95,7 +106,7 @@ protected: Names that are not valid are not added into the cache. ASSUMEs that a_PlayerNames contains lowercased player names. */ void CacheNamesToUUIDs(const AStringVector & a_PlayerNames); -} ; +} ; // tolua_export diff --git a/src/Root.h b/src/Root.h index 92a60a10d..210c36ea9 100644 --- a/src/Root.h +++ b/src/Root.h @@ -79,7 +79,7 @@ public: cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } - cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } + cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } // tolua_export /** Queues a console command for execution through the cServer class. The command will be executed in the tick thread From 17a94b16ea6207fd5f38fbd309b4db0d92de0d31 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 13:52:51 +0200 Subject: [PATCH 028/751] MojangAPI: Implemented UUID shortening and dashing. --- src/ClientHandle.cpp | 3 ++- src/ClientHandle.h | 8 +++++++- src/Protocol/Authenticator.cpp | 11 +---------- src/Protocol/MojangAPI.cpp | 34 +++++++++++++++++++++++++++------- src/Protocol/Protocol17x.cpp | 6 +++--- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index e4ad218a2..3f81f0a29 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -233,13 +233,14 @@ AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) // This guarantees that they will never collide with an online UUID and can be distinguished. // Proper format for a version 3 UUID is: // xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B + // Note that we generate a short UUID (without the dashes) // Generate an md5 checksum, and use it as base for the ID: unsigned char MD5[16]; md5((const unsigned char *)a_Username.c_str(), a_Username.length(), MD5); MD5[6] &= 0x0f; // Need to trim to 4 bits only... MD5[8] &= 0x0f; // ... otherwise %01x overflows into two chars - return Printf("%02x%02x%02x%02x-%02x%02x-3%01x%02x-8%01x%02x-%02x%02x%02x%02x%02x%02x", + return Printf("%02x%02x%02x%02x%02x%02x3%01x%02x8%01x%02x%02x%02x%02x%02x%02x%02x", MD5[0], MD5[1], MD5[2], MD5[3], MD5[4], MD5[5], MD5[6], MD5[7], MD5[8], MD5[9], MD5[10], MD5[11], diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 50ed596d5..f2183a5ca 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -66,7 +66,9 @@ public: cPlayer * GetPlayer(void) { return m_Player; } // tolua_export + /** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */ const AString & GetUUID(void) const { return m_UUID; } // tolua_export + void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; } const Json::Value & GetProperties(void) const { return m_Properties; } @@ -80,7 +82,7 @@ public: /** Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. - Returns a 36-char UUID (with dashes). */ + Returns a 32-char UUID (no dashes). */ static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export /** Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. @@ -360,7 +362,11 @@ private: int m_NumBlockChangeInteractionsThisTick; static int s_ClientCount; + + /** ID used for identification during authenticating. Assigned sequentially for each new instance. */ int m_UniqueID; + + /** Contains the UUID used by Mojang to identify the player's account. Short UUID stored here (without dashes) */ AString m_UUID; /** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */ diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index e5d16cf10..160564d51 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -188,21 +188,12 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S return false; } a_UserName = root.get("name", "Unknown").asString(); - a_UUID = root.get("id", "").asString(); + a_UUID = cMojangAPI::MakeUUIDShort(root.get("id", "").asString()); a_Properties = root["properties"]; // Store the player's UUID in the NameToUUID map in MojangAPI: cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(a_UserName, a_UUID); - // If the UUID doesn't contain the dashes, insert them at the proper places: - if (a_UUID.size() == 32) - { - a_UUID.insert(8, "-"); - a_UUID.insert(13, "-"); - a_UUID.insert(18, "-"); - a_UUID.insert(23, "-"); - } - return true; } diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 05f9c09a7..52afd71da 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -18,6 +18,9 @@ /** The maximum age for items to be kept in the cache. Any item older than this will be removed. */ const Int64 MAX_AGE = 7 * 24 * 60 * 60; // 7 days ago +/** The maximum number of names to send in a single query */ +const int MAX_PER_QUERY = 100; + @@ -29,6 +32,7 @@ const Int64 MAX_AGE = 7 * 24 * 60 * 60; // 7 days ago + /** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: Downloaded from http://certs.starfieldtech.com/repository/ */ static const AString & StarfieldCACert(void) @@ -161,9 +165,10 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) { AString lcName(a_PlayerName); + AString UUID = MakeUUIDShort(a_UUID); Int64 Now = time(NULL); cCSLock Lock(m_CSNameToUUID); - m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(a_PlayerName, a_UUID, Now); + m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(a_PlayerName, UUID, Now); } @@ -234,8 +239,14 @@ AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) case 36: { + // Remove the dashes from the string: AString res; - // TODO + res.reserve(32); + res.append(a_UUID, 0, 8); + res.append(a_UUID, 9, 4); + res.append(a_UUID, 14, 4); + res.append(a_UUID, 19, 4); + res.append(a_UUID, 24, 12); return res; } } @@ -256,7 +267,16 @@ AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) case 32: { AString res; - // TODO + res.reserve(36); + res.append(a_UUID, 0, 8); + res.push_back('-'); + res.append(a_UUID, 8, 4); + res.push_back('-'); + res.append(a_UUID, 12, 4); + res.push_back('-'); + res.append(a_UUID, 16, 4); + res.push_back('-'); + res.append(a_UUID, 20, 12); return res; } } @@ -362,11 +382,11 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) while (!NamesToQuery.empty()) { - // Create the request body - a JSON containing up to 100 playernames: + // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); - for (; (itr != end) && (Count < 100); ++itr, ++Count) + for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); @@ -377,7 +397,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) // Create the HTTP request: AString Request; - Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; + Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; @@ -430,7 +450,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); - AString JsonUUID = Val.get("id", "").asString(); + AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index dadf82716..73aba167d 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -680,7 +680,7 @@ void cProtocol172::SendLoginSuccess(void) { cPacketizer Pkt(*this, 0x02); // Login success packet - Pkt.WriteString(m_Client->GetUUID()); + Pkt.WriteString(cMojangAPI::MakeUUIDDashed(m_Client->GetUUID())); Pkt.WriteString(m_Client->GetUsername()); } @@ -941,7 +941,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet Pkt.WriteVarInt(a_Player.GetUniqueID()); - Pkt.WriteString(a_Player.GetClientHandle()->GetUUID()); + Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); Pkt.WriteString(a_Player.GetName()); Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosY()); @@ -3014,7 +3014,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet Pkt.WriteVarInt(a_Player.GetUniqueID()); - Pkt.WriteString(a_Player.GetClientHandle()->GetUUID()); + Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); Pkt.WriteString(a_Player.GetName()); const Json::Value & Properties = m_Client->GetProperties(); From afef7a79d7a214eec66e427da589172a40a18fef Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 13:53:23 +0200 Subject: [PATCH 029/751] Debuggers: Updated for the new cMojangAPI changes. --- MCServer/Plugins/Debuggers/Debuggers.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 80416acc7..575d696cb 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -287,7 +287,7 @@ function TestUUIDFromName() "nonexistent_player", } -- WARNING: Blocking operation! DO NOT USE IN TICK THREAD! - local UUIDs = cClientHandle:GetUUIDsFromPlayerNames(PlayerNames) + local UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(PlayerNames) -- Log the results: for _, name in ipairs(PlayerNames) do @@ -299,6 +299,15 @@ function TestUUIDFromName() end end + -- Test once more with the same players, valid-only. This should go directly from cache, so fast. + LOG("Testing again with the same valid players...") + local ValidPlayerNames = + { + "xoft", + "aloe_vera", + } + UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(ValidPlayerNames); + LOG("UUID-from-Name resolution test finished.") end From 5daeba7e887ecf15b2facd3801f424a5bfcaa2e6 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 13:59:47 +0200 Subject: [PATCH 030/751] Removed lighting code in cEnderman::CheckEventSeePlayer --- src/Mobs/Enderman.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 6b7a22757..9c1cb7ce3 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -116,15 +116,7 @@ void cEnderman::CheckEventSeePlayer() ASSERT(Callback.GetPlayer() != NULL); - int CX, CZ; - cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, CX, CZ); - if (!GetWorld()->IsChunkLighted(CX, CZ)) - { - GetWorld()->QueueLightChunk(CX, CZ); - return; - } - - if ((GetWorld()->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() < 15) && !Callback.GetPlayer()->IsGameModeCreative()) + if (!Callback.GetPlayer()->IsGameModeCreative()) { super::EventSeePlayer(Callback.GetPlayer()); m_EMState = CHASING; From 1793644feff66b076980c669ede94d7b03eceafe Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 14:02:36 +0200 Subject: [PATCH 031/751] APIDump: Fixed UUID-related documentation. --- 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 e5114784e..692ca80ac 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -523,12 +523,12 @@ end Functions = { - GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 36-char UUID (with dashes)." }, + GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 32-char UUID (no dashes)." }, GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." }, GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" }, GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." }, GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" }, - GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." }, + GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data. Returns a 32-char UUID (no dashes)" }, GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" }, GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" }, HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." }, From 426773df17dbd7748b51021a27119240de5b1922 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 14:03:14 +0200 Subject: [PATCH 032/751] ManualBindings: Fixed alignment. --- src/Bindings/ManualBindings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 026a6bad5..b1d302560 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -3141,9 +3141,9 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cClientHandle"); - tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); - tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); - tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); + tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); + tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cMojangAPI"); From 85d64d291a6d11df6689190268c1f4c6b1c02cdd Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 14:09:30 +0200 Subject: [PATCH 033/751] MojangAPI: Clarified the UUID conversion code. --- src/Protocol/MojangAPI.cpp | 15 +++++++++++++-- src/Protocol/MojangAPI.h | 6 ++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 52afd71da..86ff134db 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -233,9 +233,14 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) { + // Note: we only check the string's length, not the actual content switch (a_UUID.size()) { - case 32: return a_UUID; + case 32: + { + // Already is a short UUID + return a_UUID; + } case 36: { @@ -260,12 +265,18 @@ AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) { + // Note: we only check the string's length, not the actual content switch (a_UUID.size()) { - case 36: return a_UUID; + case 36: + { + // Already is a dashed UUID + return a_UUID; + } case 32: { + // Insert dashes at the proper positions: AString res; res.reserve(36); res.append(a_UUID, 0, 8); diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index cc2902a19..c99f940ad 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -36,11 +36,13 @@ public: // tolua_begin /** Converts the given UUID to its short form (32 bytes, no dashes). - Logs a warning and returns empty string if not a UUID. */ + Logs a warning and returns empty string if not a UUID. + Note: only checks the string's length, not the actual content. */ static AString MakeUUIDShort(const AString & a_UUID); /** Converts the given UUID to its dashed form (36 bytes, 4 dashes). - Logs a warning and returns empty string if not a UUID. */ + Logs a warning and returns empty string if not a UUID. + Note: only checks the string's length, not the actual content. */ static AString MakeUUIDDashed(const AString & a_UUID); // tolua_end From 5249f574bd077158836455fa66218e5fea6dcafe Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 15:55:50 +0200 Subject: [PATCH 034/751] Added RoofedForest trees. Could still be improved allot. --- src/Generating/Trees.cpp | 73 ++++++++++++++++++++++++++++++++++++++-- src/Generating/Trees.h | 2 ++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index c40322630..87405608b 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -218,7 +218,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No return; } - case biRoofedForest: case biColdTaiga: case biColdTaigaHills: case biMegaTaiga: @@ -238,7 +237,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biIcePlainsSpikes: case biJungleM: case biJungleEdgeM: - case biRoofedForestM: case biColdTaigaM: case biMegaSpruceTaiga: case biMegaSpruceTaigaHills: @@ -253,6 +251,13 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); return; } + + case biRoofedForest: + case biRoofedForestM: + { + GetRoofedForestTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + return; + } case biDesert: case biDesertHills: @@ -807,3 +812,67 @@ void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & + +void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) +{ + // Calculate a height + int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 11) % 4; + + // Creat the trunk + for (int i = 0; i < Height; i++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + + // Create branches + for (int i = 0; i < 3; i++) + { + //int x = (a_Noise.IntNoise3D(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) < 0 ? -1 : 2); + //int z = (a_Noise.IntNoise3D(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) < 0 ? -1 : 2); + int x = (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) % 3) - 1; + int z = (a_Noise.IntNoise3DInt(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) % 3) - 1; + + // The branches would end up in the trunk. + if ((x >= a_BlockX) && (x <= a_BlockX + 1) && (z >= a_BlockZ) && (z <= a_BlockZ + 1)) + { + NOISE_DATATYPE Val1 = a_Noise.IntNoise2D(x, z); + if (Val1 < 0) + { + x = a_BlockX + (Val1 < -0.5) ? -1 : 3; + } + else + { + z = a_BlockZ + (Val1 < 0.5) ? -1 : 3; + } + } + + int y = Height - (a_Noise.IntNoise3DInt(a_BlockX + x, a_BlockY * i, a_BlockZ - z) % (Height - (Height / 4))); + + for (int Y = y; Y < Height; Y++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX + x, a_BlockY + Y, a_BlockZ + z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + } + + int hei = a_BlockY + Height - 2; + + // The lower two leaves layers are BigO4 with log in the middle and possibly corners: + for (int i = 0; i < 2; i++) + { + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO4, ARRAYCOUNT(BigO4), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + hei++; + } // for i - 2* + + // The top leaves layer is a BigO3 with leaves in the middle and possibly corners: + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + a_OtherBlocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD)); +} + + + + diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 1f6ac4dff..2b2e0acc3 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -96,6 +96,8 @@ void GetLargeJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & /// Generates an image of a small jungle tree (1x1 trunk) void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); +/// Generates an image of a roofed tree forest tree +void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); From a71c2da3f8ee329977902a36274d720908a77c48 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 17:07:57 +0200 Subject: [PATCH 035/751] APIDump: Added notes about cache to cMojangAPI. --- MCServer/Plugins/APIDump/APIDesc.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 692ca80ac..2a8ae90f9 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1619,7 +1619,13 @@ a_Player:OpenWindow(Window); Mojang uses two formats for UUIDs, short and dashed. MCServer works with short UUIDs internally, but will convert to dashed UUIDs where needed - in the protocol login for example. The MakeUUIDShort() and MakeUUIDDashed() functions are provided for plugins to use for conversion between the two - formats. + formats.

+

+ This class will cache values returned by the API service. The cache will hold the values for 7 days + by default, after that, they will no longer be available. This is in order to not let the server get + banned from using the API service, since they are rate-limited to 600 queries per 10 minutes. The + cache contents also gets updated whenever a player successfully joins, since that makes the server + contact the API service, too, and retrieve the relevant data.

]], Functions = { From 17b679f355b8a63175815418983662c17ee13686 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 17:09:00 +0200 Subject: [PATCH 036/751] Fixed compiling using Clang --- src/Generating/Trees.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 87405608b..fb46a5e3b 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -830,8 +830,6 @@ void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & // Create branches for (int i = 0; i < 3; i++) { - //int x = (a_Noise.IntNoise3D(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) < 0 ? -1 : 2); - //int z = (a_Noise.IntNoise3D(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) < 0 ? -1 : 2); int x = (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) % 3) - 1; int z = (a_Noise.IntNoise3DInt(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) % 3) - 1; @@ -841,11 +839,11 @@ void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & NOISE_DATATYPE Val1 = a_Noise.IntNoise2D(x, z); if (Val1 < 0) { - x = a_BlockX + (Val1 < -0.5) ? -1 : 3; + x = a_BlockX + ((Val1 < -0.5) ? -1 : 3); } else { - z = a_BlockZ + (Val1 < 0.5) ? -1 : 3; + z = a_BlockZ + ((Val1 < 0.5) ? -1 : 3); } } From 0336e12cee0a784b076b5f9423bce2b9f803d1c8 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 30 Jul 2014 17:09:41 +0200 Subject: [PATCH 037/751] MojangAPI: Renamed cache file to MojangAPI.sqlite. --- 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 86ff134db..5fbc5b476 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -304,7 +304,7 @@ void cMojangAPI::LoadCachesFromDisk(void) try { // Open up the SQLite DB: - SQLite::Database db("NameToUUID.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); // Clean up old entries: @@ -341,7 +341,7 @@ void cMojangAPI::SaveCachesToDisk(void) try { // Open up the SQLite DB: - SQLite::Database db("NameToUUID.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); // Remove all entries: From c4e6a1423506c253974c7512a4b9b854a1e41b54 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 19:18:11 +0200 Subject: [PATCH 038/751] Added lighting code and added comments --- src/Mobs/Enderman.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 9c1cb7ce3..f1f366d3b 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -116,6 +116,23 @@ void cEnderman::CheckEventSeePlayer() ASSERT(Callback.GetPlayer() != NULL); + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); + + // Check if the chunk the enderman is in is lit. + if (!m_World->IsChunkLighted(ChunkX, ChunkZ)) + { + m_World->QueueLightChunk(ChunkX, ChunkZ); + return; + } + + // Enderman only attack if the skylight is higher than 6 + if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) <= 7) + { + // TODO: Teleport the enderman to a random spot. + return; + } + if (!Callback.GetPlayer()->IsGameModeCreative()) { super::EventSeePlayer(Callback.GetPlayer()); From fd2d338a252a4c230e54e25a8695d7084a924bbe Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 21:42:48 +0200 Subject: [PATCH 039/751] Fixed comment at the end of a for-loop --- src/Generating/Trees.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index fb46a5e3b..308947ad0 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -863,7 +863,7 @@ void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO4, ARRAYCOUNT(BigO4), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); hei++; - } // for i - 2* + } // for i < 2 // The top leaves layer is a BigO3 with leaves in the middle and possibly corners: PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); From f232ef5cd606d31068a758b3e784f33ca1860af0 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 21:50:02 +0200 Subject: [PATCH 040/751] Fixed doxy comment --- src/Generating/Trees.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 2b2e0acc3..2c54fce82 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -96,7 +96,7 @@ void GetLargeJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & /// Generates an image of a small jungle tree (1x1 trunk) void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); -/// Generates an image of a roofed tree forest tree +/// Generates an image of a roofed forest tree void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); From 6e0a8d393bafd0b018f168c4ef7a651a2955c1e8 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 21:56:33 +0200 Subject: [PATCH 041/751] Moved GetRoofedForestTreeImage content to GetDarkoakTreeImage --- src/Generating/Trees.cpp | 119 ++++++++++++++++++--------------------- src/Generating/Trees.h | 2 - 2 files changed, 55 insertions(+), 66 deletions(-) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 308947ad0..4786cad5a 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -255,7 +255,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biRoofedForest: case biRoofedForestM: { - GetRoofedForestTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + GetDarkoakTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); return; } @@ -412,7 +412,60 @@ void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noi void GetDarkoakTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { - // TODO + // Calculate a height + int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 11) % 4; + + // Creat the trunk + for (int i = 0; i < Height; i++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + + // Create branches + for (int i = 0; i < 3; i++) + { + int x = (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) % 3) - 1; + int z = (a_Noise.IntNoise3DInt(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) % 3) - 1; + + // The branches would end up in the trunk. + if ((x >= a_BlockX) && (x <= a_BlockX + 1) && (z >= a_BlockZ) && (z <= a_BlockZ + 1)) + { + NOISE_DATATYPE Val1 = a_Noise.IntNoise2D(x, z); + if (Val1 < 0) + { + x = a_BlockX + ((Val1 < -0.5) ? -1 : 3); + } + else + { + z = a_BlockZ + ((Val1 < 0.5) ? -1 : 3); + } + } + + int y = Height - (a_Noise.IntNoise3DInt(a_BlockX + x, a_BlockY * i, a_BlockZ - z) % (Height - (Height / 4))); + + for (int Y = y; Y < Height; Y++) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX + x, a_BlockY + Y, a_BlockZ + z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); + } + } + + int hei = a_BlockY + Height - 2; + + // The lower two leaves layers are BigO4 with log in the middle and possibly corners: + for (int i = 0; i < 2; i++) + { + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO4, ARRAYCOUNT(BigO4), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + hei++; + } // for i < 2 + + // The top leaves layer is a BigO3 with leaves in the middle and possibly corners: + PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); + a_OtherBlocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD)); } @@ -812,65 +865,3 @@ void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & - -void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) -{ - // Calculate a height - int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 11) % 4; - - // Creat the trunk - for (int i = 0; i < Height; i++) - { - a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); - a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); - a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); - a_LogBlocks.push_back(sSetBlock(a_BlockX + 1, a_BlockY + i, a_BlockZ + 1, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); - } - - // Create branches - for (int i = 0; i < 3; i++) - { - int x = (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY * i, a_BlockZ + 32 * a_Seq) % 3) - 1; - int z = (a_Noise.IntNoise3DInt(a_BlockX - 32 * a_Seq, a_BlockY * i, a_BlockZ - 32 * a_Seq) % 3) - 1; - - // The branches would end up in the trunk. - if ((x >= a_BlockX) && (x <= a_BlockX + 1) && (z >= a_BlockZ) && (z <= a_BlockZ + 1)) - { - NOISE_DATATYPE Val1 = a_Noise.IntNoise2D(x, z); - if (Val1 < 0) - { - x = a_BlockX + ((Val1 < -0.5) ? -1 : 3); - } - else - { - z = a_BlockZ + ((Val1 < 0.5) ? -1 : 3); - } - } - - int y = Height - (a_Noise.IntNoise3DInt(a_BlockX + x, a_BlockY * i, a_BlockZ - z) % (Height - (Height / 4))); - - for (int Y = y; Y < Height; Y++) - { - a_LogBlocks.push_back(sSetBlock(a_BlockX + x, a_BlockY + Y, a_BlockZ + z, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); - } - } - - int hei = a_BlockY + Height - 2; - - // The lower two leaves layers are BigO4 with log in the middle and possibly corners: - for (int i = 0; i < 2; i++) - { - PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO4, ARRAYCOUNT(BigO4), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); - PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); - hei++; - } // for i < 2 - - // The top leaves layer is a BigO3 with leaves in the middle and possibly corners: - PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); - PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 3, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD); - a_OtherBlocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_NEW_LEAVES, E_META_NEW_LEAVES_DARK_OAK_WOOD)); -} - - - - diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 2c54fce82..1f6ac4dff 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -96,8 +96,6 @@ void GetLargeJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & /// Generates an image of a small jungle tree (1x1 trunk) void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); -/// Generates an image of a roofed forest tree -void GetRoofedForestTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); From 89b1bbdc5fca5a51df1a5dd18ce91f27cb667c04 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 21:59:35 +0200 Subject: [PATCH 042/751] Added beacon. --- src/BlockEntities/BeaconEntity.cpp | 333 +++++++++++++++++++++++--- src/BlockEntities/BeaconEntity.h | 58 ++++- src/BlockEntities/FlowerPotEntity.cpp | 2 +- src/Blocks/BlockHandler.cpp | 1 + src/Blocks/BlockPiston.h | 1 + src/ChunkMap.cpp | 1 + src/ClientHandle.cpp | 54 +++++ src/ClientHandle.h | 5 +- src/Protocol/Protocol17x.cpp | 15 ++ src/UI/SlotArea.cpp | 195 +++++++++++++++ src/UI/SlotArea.h | 29 +++ src/UI/Window.cpp | 31 +++ src/UI/Window.h | 21 ++ 13 files changed, 701 insertions(+), 45 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 4b9662797..af6c124c0 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -3,33 +3,31 @@ #include "BeaconEntity.h" #include "../BlockArea.h" +#include "../Entities/Player.h" -cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World) +cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) + : super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World) + , m_IsActive(false) + , m_BeaconLevel(0) + , m_PrimaryPotion(cEntityEffect::effNoEffect) + , m_SecondaryPotion(cEntityEffect::effNoEffect) { + UpdateBeacon(); } -int cBeaconEntity::GetPyramidLevel(void) +char cBeaconEntity::CalculatePyramidLevel(void) { cBlockArea Area; - int MinY = GetPosY() - 4; - if (MinY < 0) - { - MinY = 0; - } - int MaxY = GetPosY() - 1; - if (MaxY < 0) - { - MaxY = 0; - } + int MinY = std::max(GetPosY() - 4, 0); + int MaxY = std::max(GetPosY() - 1, 0); Area.Read( m_World, @@ -42,7 +40,7 @@ int cBeaconEntity::GetPyramidLevel(void) int Layer = 1; int MiddleXZ = 4; - for (int Y = Area.GetSizeY() - 1; Y > 0; Y--) + for (int Y = (Area.GetSizeY() - 1); Y >= 0; Y--) { for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++) { @@ -50,14 +48,122 @@ int cBeaconEntity::GetPyramidLevel(void) { if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z))) { - return Layer - 1; + return (Layer - 1); } } } Layer++; } - return Layer - 1; + return (Layer - 1); +} + + + + + +bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel) +{ + if (a_Potion == cEntityEffect::effNoEffect) + { + return true; + } + + switch (a_BeaconLevel) + { + case 4: + { + // Beacon level 4 + if (a_Potion == cEntityEffect::effRegeneration) + { + return true; + } + } + case 3: + { + // Beacon level 3 + if (a_Potion == cEntityEffect::effStrength) + { + return true; + } + } + case 2: + { + // Beacon level 2 + switch (a_Potion) + { + case cEntityEffect::effResistance: + case cEntityEffect::effJumpBoost: + { + return true; + } + } + } + case 1: + { + // Beacon level 1 + switch (a_Potion) + { + case cEntityEffect::effSpeed: + case cEntityEffect::effHaste: + { + return true; + } + } + } + } + return false; +} + + + + + +bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion) +{ + LOG("SelectPrimaryPotion!"); + if (!IsValidPotion(a_Potion, m_BeaconLevel)) + { + LOG("FALLSE!"); + return false; + } + + m_PrimaryPotion = a_Potion; + return true; +} + + + + + +bool cBeaconEntity::SelectSecondaryPotion(cEntityEffect::eType a_Potion) +{ + if (!IsValidPotion(a_Potion, m_BeaconLevel)) + { + return false; + } + + m_SecondaryPotion = a_Potion; + return true; +} + + + + + +bool cBeaconEntity::IsBeaconBlocked(void) +{ + bool IsBlocked = false; + for (int Y = m_PosY; Y < cChunkDef::Height; ++Y) + { + BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ); + if (!cBlockInfo::IsTransparent(Block)) + { + IsBlocked = true; + break; + } + } + return IsBlocked; } @@ -83,8 +189,102 @@ bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType) +void cBeaconEntity::UpdateBeacon(void) +{ + if (IsBeaconBlocked()) + { + m_IsActive = false; + m_BeaconLevel = 0; + } + else + { + m_BeaconLevel = CalculatePyramidLevel(); + m_IsActive = (m_BeaconLevel > 0); + } + + // TODO: Add achievement +} + + + + + +void cBeaconEntity::GiveEffects(void) +{ + if (!m_IsActive || (m_BeaconLevel < 0)) + { + return; + } + + int Radius = m_BeaconLevel * 10 + 10; + short EffectLevel = 0; + if ((m_BeaconLevel >= 4) && (m_PrimaryPotion == m_SecondaryPotion)) + { + EffectLevel = 1; + } + + cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect; + if ((m_BeaconLevel >= 4) && (m_PrimaryPotion != m_SecondaryPotion) && (m_SecondaryPotion > 0)) + { + SecondaryPotion = m_SecondaryPotion; + } + + class cPlayerCallback : public cPlayerListCallback + { + int m_Radius; + int m_PosX, m_PosY, m_PosZ; + cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion; + short m_EffectLevel; + + virtual bool Item(cPlayer * a_Player) + { + Vector3d PlayerPosition = Vector3d(a_Player->GetPosition()); + if (PlayerPosition.y > (double)m_PosY) + { + PlayerPosition.y = (double)m_PosY; + } + + // TODO: Vanilla minecraft uses an AABB check instead of a radius one + Vector3d BeaconPosition = Vector3d(m_PosX, m_PosY, m_PosZ); + if ((PlayerPosition - BeaconPosition).Length() <= m_Radius) + { + a_Player->AddEntityEffect(m_PrimaryPotion, 180, m_EffectLevel); + + if (m_SecondaryPotion != cEntityEffect::effNoEffect) + { + a_Player->AddEntityEffect(m_SecondaryPotion, 180, 0); + } + } + return false; + } + + public: + cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryPotion, cEntityEffect::eType a_SecondaryPotion, short a_EffectLevel) + : m_Radius(a_Radius) + , m_PosX(a_PosX) + , m_PosY(a_PosY) + , m_PosZ(a_PosZ) + , m_PrimaryPotion(a_PrimaryPotion) + , m_SecondaryPotion(a_SecondaryPotion) + , m_EffectLevel(a_EffectLevel) + {}; + + } PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryPotion, SecondaryPotion, EffectLevel); + GetWorld()->ForEachPlayer(PlayerCallback); +} + + + + + bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) { + // Update the beacon every 4 seconds + if ((GetWorld()->GetWorldAge() % 80) == 0) + { + UpdateBeacon(); + GiveEffects(); + } return false; } @@ -92,23 +292,94 @@ bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) -void cBeaconEntity::SaveToJson(Json::Value& a_Value) -{ -} - - - - -void cBeaconEntity::SendTo(cClientHandle & a_Client) -{ -} - - - - - void cBeaconEntity::UsedBy(cPlayer * a_Player) { + cWindow * Window = GetWindow(); + if (Window == NULL) + { + OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this)); + Window = GetWindow(); + } + + if (Window != NULL) + { + // if (a_Player->GetWindow() != Window) + // -> Because mojang doesn't send a 'close window' packet when you click the cancel button in the beacon inventory ... + { + a_Player->OpenWindow(Window); + } + } +} + + + + + +bool cBeaconEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_PosX = a_Value.get("x", 0).asInt(); + m_PosY = a_Value.get("y", 0).asInt(); + m_PosZ = a_Value.get("z", 0).asInt(); + + Json::Value AllSlots = a_Value.get("Slots", 0); + int SlotIdx = 0; + for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr) + { + cItem Item; + Item.FromJson(*itr); + SetSlot(SlotIdx, Item); + SlotIdx++; + } + + m_BeaconLevel = (char)a_Value.get("Level", 0).asInt(); + int PrimaryPotion = a_Value.get("PrimaryPotion", 0).asInt(); + int SecondaryPotion = a_Value.get("SecondaryPotion", 0).asInt(); + + if ((PrimaryPotion >= 0) && (PrimaryPotion <= (int)cEntityEffect::effSaturation)) + { + m_PrimaryPotion = (cEntityEffect::eType)PrimaryPotion; + } + + if ((SecondaryPotion >= 0) && (SecondaryPotion <= (int)cEntityEffect::effSaturation)) + { + m_SecondaryPotion = (cEntityEffect::eType)SecondaryPotion; + } + + return true; +} + + + + + +void cBeaconEntity::SaveToJson(Json::Value& a_Value) +{ + a_Value["x"] = m_PosX; + a_Value["y"] = m_PosY; + a_Value["z"] = m_PosZ; + + Json::Value AllSlots; + int NumSlots = m_Contents.GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + Json::Value Slot; + m_Contents.GetSlot(i).GetJson(Slot); + AllSlots.append(Slot); + } + a_Value["Slots"] = AllSlots; + + a_Value["Level"] = m_BeaconLevel; + a_Value["PrimaryPotion"] = (int)m_PrimaryPotion; + a_Value["SecondaryPotion"] = (int)m_SecondaryPotion; +} + + + + + +void cBeaconEntity::SendTo(cClientHandle & a_Client) +{ + a_Client.SendUpdateBlockEntity(*this); } diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index ee1eda391..52111e82a 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -1,7 +1,7 @@ #pragma once -#include "BlockEntity.h" +#include "BlockEntityWithItems.h" @@ -17,26 +17,60 @@ namespace Json class cBeaconEntity : - public cBlockEntity + public cBlockEntityWithItems { - typedef cBlockEntity super; + typedef cBlockEntityWithItems super; public: - - /** The initial constructor */ cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - - /** Returns the amount of layers the pyramid below the beacon has. */ - int GetPyramidLevel(void); + + /** Is the beacon active? */ + bool IsActive(void) const { return m_IsActive; } + + /** Returns the beacon level. (0 - 4) */ + char GetBeaconLevel(void) const { return m_BeaconLevel; } + + char GetPrimaryPotion(void) const { return m_PrimaryPotion; } + char GetSecondaryPotion(void) const { return m_SecondaryPotion; } + + /** Select the primary potion. Returns false when the potion is invalid.*/ + bool SelectPrimaryPotion(cEntityEffect::eType a_Potion); + + /** Select the secondary potion. Returns false when the potion is invalid. */ + bool SelectSecondaryPotion(cEntityEffect::eType a_Potion); + + /** Calculate the amount of layers the pyramid below the beacon has. */ + char CalculatePyramidLevel(void); + + /** Is the beacon blocked by non-transparent blocks that are higher than the beacon? */ + bool IsBeaconBlocked(void); /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ static bool IsMineralBlock(BLOCKTYPE a_BlockType); + + /** Returns true if the potion can be used. */ + static bool IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel); + + /** Update the beacon. */ + void UpdateBeacon(void); + + /** Give the near-players the effects. */ + void GiveEffects(void); + + bool LoadFromJson(const Json::Value & a_Value); // cBlockEntity overrides: - virtual void SaveToJson(Json::Value& a_Value) override; - virtual void SendTo(cClientHandle & a_Client) override; - virtual void UsedBy(cPlayer * a_Player) override; - virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override; + virtual void SaveToJson(Json::Value& a_Value) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void UsedBy(cPlayer * a_Player) override; + +protected: + bool m_IsActive; + char m_BeaconLevel; + + cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion; + } ; diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp index 87bf8b921..e001634b8 100644 --- a/src/BlockEntities/FlowerPotEntity.cpp +++ b/src/BlockEntities/FlowerPotEntity.cpp @@ -1,7 +1,7 @@ // FlowerPotEntity.cpp -// Implements the cFlowerPotEntity class representing a single sign in the world +// Implements the cFlowerPotEntity class representing a single flower pot in the world #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "json/json.h" diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index ddb0186c9..52f7dd608 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -181,6 +181,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); + case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType); case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index bbb8af75b..0bec603e3 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -94,6 +94,7 @@ private: switch (a_BlockType) { case E_BLOCK_ANVIL: + case E_BLOCK_BEACON: case E_BLOCK_BEDROCK: case E_BLOCK_BREWING_STAND: case E_BLOCK_CHEST: diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 05d219918..38e0cd82d 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1839,6 +1839,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } case E_BLOCK_OBSIDIAN: + case E_BLOCK_BEACON: case E_BLOCK_BEDROCK: case E_BLOCK_WATER: case E_BLOCK_LAVA: diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 30ec737be..849de2ce1 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -31,6 +31,7 @@ #include "Items/ItemSword.h" #include "polarssl/md5.h" +#include "BlockEntities/BeaconEntity.h" @@ -659,6 +660,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); } + else if (a_Channel == "MC|Beacon") + { + HandleBeaconSelection(a_Message.c_str(), a_Message.size()); + } else if (a_Channel == "MC|ItemName") { HandleAnvilItemName(a_Message.c_str(), a_Message.size()); @@ -746,6 +751,55 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList +void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) +{ + if (a_Length < 14) + { + SendChat("Failure setting beacon selection; bad request", mtFailure); + LOGD("Malformed MC|Beacon packet."); + return; + } + + cWindow * Window = m_Player->GetWindow(); + if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon)) + { + return; + } + cBeaconWindow * BeaconWindow = (cBeaconWindow *) Window; + + if (Window->GetSlot(*m_Player, 0)->IsEmpty()) + { + return; + } + + cByteBuffer Buffer(a_Length); + Buffer.Write(a_Data, a_Length); + + int PrimaryPotionID, SecondaryPotionID; + Buffer.ReadBEInt(PrimaryPotionID); + Buffer.ReadBEInt(SecondaryPotionID); + + cEntityEffect::eType PrimaryPotion = cEntityEffect::effNoEffect; + if ((PrimaryPotionID >= 0) && (PrimaryPotionID <= (int)cEntityEffect::effSaturation)) + { + PrimaryPotion = (cEntityEffect::eType)PrimaryPotionID; + } + + cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect; + if ((SecondaryPotionID >= 0) && (SecondaryPotionID <= (int)cEntityEffect::effSaturation)) + { + SecondaryPotion = (cEntityEffect::eType)SecondaryPotionID; + } + + Window->SetSlot(*m_Player, 0, cItem()); + BeaconWindow->GetBeaconEntity()->SelectPrimaryPotion(PrimaryPotion); + BeaconWindow->GetBeaconEntity()->SelectSecondaryPotion(SecondaryPotion); +} + + + + + void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length) { if (a_Length < 14) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 48eba4de1..f3f1da417 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -399,7 +399,10 @@ private: /** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */ void UnregisterPluginChannels(const AStringVector & a_ChannelList); - + + /** Handles the "MC|Beacon" plugin message */ + void HandleBeaconSelection(const char * a_Data, size_t a_Length); + /** Handles the "MC|AdvCdm" plugin message */ void HandleCommandBlockMessage(const char * a_Data, size_t a_Length); diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 45d39e0e9..8a68edd1f 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -37,6 +37,7 @@ Implements the 1.7.x protocol classes: #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" @@ -1328,6 +1329,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text + case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; @@ -2581,6 +2583,19 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt switch (a_BlockEntity.GetBlockType()) { + case E_BLOCK_BEACON: + { + cBeaconEntity & BeaconEntity = (cBeaconEntity &)a_BlockEntity; + + Writer.AddInt("x", BeaconEntity.GetPosX()); + Writer.AddInt("y", BeaconEntity.GetPosY()); + Writer.AddInt("z", BeaconEntity.GetPosZ()); + Writer.AddInt("Primary", BeaconEntity.GetPrimaryPotion()); + Writer.AddInt("Secondary", BeaconEntity.GetSecondaryPotion()); + Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); + Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + break; + } case E_BLOCK_COMMAND_BLOCK: { cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index b5f84c24c..4199bbf56 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "SlotArea.h" #include "../Entities/Player.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" @@ -1190,6 +1191,200 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) +//////////////////////////////////////////////////////////////////////////////// +// cSlotAreaBeacon: + +cSlotAreaBeacon::cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow) : + cSlotArea(1, a_ParentWindow), + m_Beacon(a_Beacon) +{ + m_Beacon->GetContents().AddListener(*this); +} + + + + + +cSlotAreaBeacon::~cSlotAreaBeacon() +{ + m_Beacon->GetContents().RemoveListener(*this); +} + + + + +bool cSlotAreaBeacon::IsPlaceableItem(short a_ItemType) +{ + switch (a_ItemType) + { + case E_ITEM_EMERALD: + case E_ITEM_DIAMOND: + case E_ITEM_GOLD: + case E_ITEM_IRON: + { + return true; + } + } + return false; +} + + + + + +void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + switch (a_ClickAction) + { + case caShiftLeftClick: + case caShiftRightClick: + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + case caMiddleClick: + { + MiddleClicked(a_Player, a_SlotNum); + return; + } + case caDropKey: + case caCtrlDropKey: + { + DropClicked(a_Player, a_SlotNum, false); + return; + } + case caNumber1: + case caNumber2: + case caNumber3: + case caNumber4: + case caNumber5: + case caNumber6: + case caNumber7: + case caNumber8: + case caNumber9: + { + NumberClicked(a_Player, a_SlotNum, a_ClickAction); + return; + } + default: + { + break; + } + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot; + Slot.Empty(); + } + else if (Slot.IsEmpty()) + { + if (!IsPlaceableItem(DraggingItem.m_ItemType)) + { + return; + } + + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + else if (DraggingItem.m_ItemCount == 1) + { + if (!IsPlaceableItem(DraggingItem.m_ItemCount)) + { + return; + } + + // Switch contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +{ + const cItem * Slot = GetSlot(0, a_Player); + if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1)) + { + return; + } + + if (a_ShouldApply) + { + SetSlot(0, a_Player, a_ItemStack.CopyOne()); + } + a_ItemStack.Empty(); +} + + + + + +const cItem * cSlotAreaBeacon::GetSlot(int a_SlotNum, cPlayer & a_Player) const +{ + UNUSED(a_Player); + return &(m_Beacon->GetSlot(a_SlotNum)); +} + + + + + +void cSlotAreaBeacon::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + UNUSED(a_Player); + m_Beacon->SetSlot(a_SlotNum, a_Item); +} + + + + + +void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) +{ + UNUSED(a_SlotNum); + // Something has changed in the window, broadcast the entire window to all clients + ASSERT(a_ItemGrid == &(m_Beacon->GetContents())); + + m_ParentWindow.BroadcastWholeWindow(); +} + + + + //////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index fa842bb81..9a96f2f3c 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -15,6 +15,7 @@ class cWindow; class cPlayer; +class cBeaconEntity; class cChestEntity; class cDropSpenserEntity; class cEnderChestEntity; @@ -314,6 +315,34 @@ protected: +class cSlotAreaBeacon : + public cSlotArea, + public cItemGrid::cListener +{ + typedef cSlotArea super; + +public: + cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow); + virtual ~cSlotAreaBeacon(); + + bool IsPlaceableItem(short a_ItemType); + + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; + +protected: + cBeaconEntity * m_Beacon; + + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; +} ; + + + + + class cSlotAreaEnchanting : public cSlotAreaTemporary { diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 4731f282b..aa129bfe8 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -9,6 +9,7 @@ #include "../Entities/Pickup.h" #include "../Inventory.h" #include "../Items/ItemHandler.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/EnderChestEntity.h" @@ -840,6 +841,36 @@ void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +//////////////////////////////////////////////////////////////////////////////// +// cBeaconWindow: + +cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) : + cWindow(wtBeacon, "Beacon"), + m_Beacon(a_Beacon) +{ + m_ShouldDistributeToHotbarFirst = true; + m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player) +{ + super::OpenedByPlayer(a_Player); + + a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryPotion()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryPotion()); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cEnchantingWindow: diff --git a/src/UI/Window.h b/src/UI/Window.h index 97db0ca88..9fb0e3b38 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -23,6 +23,7 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; +class cBeaconEntity; class cSlotArea; class cSlotAreaAnvil; class cWorld; @@ -258,6 +259,26 @@ protected: +class cBeaconWindow : + public cWindow +{ + typedef cWindow super; +public: + cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon); + + cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; } + + // cWindow Overrides: + virtual void OpenedByPlayer(cPlayer & a_Player) override; + +protected: + cBeaconEntity * m_Beacon; +} ; + + + + + class cEnchantingWindow : public cWindow { From 81e095adda62e4067ab4c07b0e4c7ce0f3dbce39 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 22:19:51 +0200 Subject: [PATCH 043/751] Exported the beacon. --- src/Bindings/AllToLua.pkg | 1 + src/Bindings/CMakeLists.txt | 1 + src/Bindings/ManualBindings.cpp | 2 ++ src/BlockEntities/BeaconEntity.cpp | 2 -- src/BlockEntities/BeaconEntity.h | 42 +++++++++++++++++++----------- src/Chunk.cpp | 33 +++++++++++++++++++++++ src/Chunk.h | 5 ++++ src/ChunkMap.cpp | 18 +++++++++++++ src/ChunkMap.h | 5 ++++ src/World.cpp | 10 +++++++ src/World.h | 5 ++++ 11 files changed, 107 insertions(+), 17 deletions(-) diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 1e5dfd2fe..621358662 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -47,6 +47,7 @@ $cfile "../Inventory.h" $cfile "../Enchantments.h" $cfile "../Item.h" $cfile "../ItemGrid.h" +$cfile "../BlockEntities/BeaconEntity.h" $cfile "../BlockEntities/BlockEntity.h" $cfile "../BlockEntities/BlockEntityWithItems.h" $cfile "../BlockEntities/ChestEntity.h" diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 48e7ce79c..a2b381a26 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -53,6 +53,7 @@ set(BINDING_DEPENDENCIES ../Bindings/WebPlugin.h ../BiomeDef.h ../BlockArea.h + ../BlockEntities/BeaconEntity.h ../BlockEntities/BlockEntity.h ../BlockEntities/BlockEntityWithItems.h ../BlockEntities/ChestEntity.h diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index df9687fc0..460d879d5 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -16,6 +16,7 @@ #include "../WebAdmin.h" #include "../ClientHandle.h" #include "../BlockArea.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -2996,6 +2997,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cWorld"); tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ); + tolua_function(tolua_S, "DoWithBeaconAt", tolua_DoWithXYZ); tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ); tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ); tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ); diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index af6c124c0..38b710181 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -121,10 +121,8 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion) { - LOG("SelectPrimaryPotion!"); if (!IsValidPotion(a_Potion, m_BeaconLevel)) { - LOG("FALLSE!"); return false; } diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 52111e82a..4710e91e0 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -1,3 +1,10 @@ +// BeaconEntity.h + +// Declares the cBeaconEntity class representing a single beacon in the world + + + + #pragma once @@ -16,14 +23,26 @@ namespace Json +// tolua_begin class cBeaconEntity : public cBlockEntityWithItems { typedef cBlockEntityWithItems super; public: + // tolua_end + cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); + bool LoadFromJson(const Json::Value & a_Value); + // cBlockEntity overrides: + virtual void SaveToJson(Json::Value& a_Value) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void UsedBy(cPlayer * a_Player) override; + + // tolua_begin + /** Is the beacon active? */ bool IsActive(void) const { return m_IsActive; } @@ -45,33 +64,26 @@ public: /** Is the beacon blocked by non-transparent blocks that are higher than the beacon? */ bool IsBeaconBlocked(void); - /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ - static bool IsMineralBlock(BLOCKTYPE a_BlockType); - - /** Returns true if the potion can be used. */ - static bool IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel); - /** Update the beacon. */ void UpdateBeacon(void); /** Give the near-players the effects. */ void GiveEffects(void); - bool LoadFromJson(const Json::Value & a_Value); - - // cBlockEntity overrides: - virtual void SaveToJson(Json::Value& a_Value) override; - virtual void SendTo(cClientHandle & a_Client) override; - virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void UsedBy(cPlayer * a_Player) override; + /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ + static bool IsMineralBlock(BLOCKTYPE a_BlockType); + + /** Returns true if the potion can be used. */ + static bool IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel); + + // tolua_end protected: bool m_IsActive; char m_BeaconLevel; cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion; - -} ; +} ; // tolua_export diff --git a/src/Chunk.cpp b/src/Chunk.cpp index b83036b6d..cd7dc698c 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -11,6 +11,7 @@ #include "Server.h" #include "zlib/zlib.h" #include "Defines.h" +#include "BlockEntities/BeaconEntity.h" #include "BlockEntities/ChestEntity.h" #include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DropperEntity.h" @@ -2126,6 +2127,38 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc +bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + if ((*itr)->GetBlockType() != E_BLOCK_BEACON) + { + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; + } + + // The correct block entity is here + if (a_Callback.Item((cBeaconEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index 7eee3999c..5cde3f08f 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -28,6 +28,7 @@ class cServer; class MTRand; class cPlayer; class cChunkMap; +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cFurnaceEntity; @@ -45,6 +46,7 @@ class cMobSpawner; typedef std::list cClientHandleList; typedef cItemCallback cEntityCallback; +typedef cItemCallback cBeaconCallback; typedef cItemCallback cChestCallback; typedef cItemCallback cDispenserCallback; typedef cItemCallback cFurnaceCallback; @@ -236,6 +238,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 38e0cd82d..dd8be0631 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -2116,6 +2116,24 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB +bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { int ChunkX, ChunkZ; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index e33d9f894..1e9a0f982 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -19,6 +19,7 @@ class MTRand; class cChunkStay; class cChunk; class cPlayer; +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cDropperEntity; @@ -40,6 +41,7 @@ typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; typedef cItemCallback cEntityCallback; typedef cItemCallback cBlockEntityCallback; +typedef cItemCallback cBeaconCallback; typedef cItemCallback cChestCallback; typedef cItemCallback cDispenserCallback; typedef cItemCallback cDropperCallback; @@ -234,6 +236,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible diff --git a/src/World.cpp b/src/World.cpp index 348498693..b3c4b1de0 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -25,6 +25,7 @@ #include "Entities/TNTEntity.h" #include "BlockEntities/CommandBlockEntity.h" +#include "BlockEntities/BeaconEntity.h" // Simulators: #include "Simulator/SimulatorManager.h" @@ -1232,6 +1233,15 @@ bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc +bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback& a_Callback) +{ + return m_ChunkMap->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); diff --git a/src/World.h b/src/World.h index 4d0ccf2dd..90b798e8e 100644 --- a/src/World.h +++ b/src/World.h @@ -41,6 +41,7 @@ class cEntity; class cBlockEntity; class cWorldGenerator; // The generator that actually generates the chunks for a single world class cChunkGenerator; // The thread responsible for generating chunks +class cBeaconEntity; class cChestEntity; class cDispenserEntity; class cFlowerPotEntity; @@ -59,6 +60,7 @@ typedef std::vector cSetChunkDataPtrs; typedef cItemCallback cPlayerListCallback; typedef cItemCallback cEntityCallback; +typedef cItemCallback cBeaconCallback; typedef cItemCallback cChestCallback; typedef cItemCallback cDispenserCallback; typedef cItemCallback cFurnaceCallback; @@ -523,6 +525,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp + /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ + bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Exported in ManualBindings.cpp + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp From ad4fa6eba823de90f528e199c9f7e61bdb3f55f3 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 22:22:06 +0200 Subject: [PATCH 044/751] Changed return type from GetPrimaryPotion() and GetSecondaryPotion() --- src/BlockEntities/BeaconEntity.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 4710e91e0..07b2b85dc 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -49,8 +49,8 @@ public: /** Returns the beacon level. (0 - 4) */ char GetBeaconLevel(void) const { return m_BeaconLevel; } - char GetPrimaryPotion(void) const { return m_PrimaryPotion; } - char GetSecondaryPotion(void) const { return m_SecondaryPotion; } + cEntityEffect::eType GetPrimaryPotion(void) const { return m_PrimaryPotion; } + cEntityEffect::eType GetSecondaryPotion(void) const { return m_SecondaryPotion; } /** Select the primary potion. Returns false when the potion is invalid.*/ bool SelectPrimaryPotion(cEntityEffect::eType a_Potion); From 66d34b83d27a72ed4cc2598527c25dfb8c1a873c Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 22:31:43 +0200 Subject: [PATCH 045/751] Added beacon documentation. --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + .../Plugins/APIDump/Classes/BlockEntities.lua | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index e65da1d16..2a592e1e1 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2244,6 +2244,7 @@ end DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." }, DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." }, DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature:
function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])
The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." }, + DoWithBeaconAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a beacon at the specified coords, calls the CallbackFunction with the {{cBeaconEntity}} parameter representing the beacon. The CallbackFunction has the following signature:
function Callback({{cBeaconEntity|BeaconEntity}}, [CallbackData])
The function returns false if there is no beacon, or if there is, it returns the bool value that the callback has returned." }, DoWithChestAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature:
function Callback({{cChestEntity|ChestEntity}}, [CallbackData])
The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." }, DoWithCommandBlockAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a command block at the specified coords, calls the CallbackFunction with the {{cCommandBlockEntity}} parameter representing the command block. The CallbackFunction has the following signature:
function Callback({{cCommandBlockEntity|CommandBlockEntity}}, [CallbackData])
The function returns false if there is no command block, or if there is, it returns the bool value that the callback has returned." }, DoWithDispenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dispenser at the specified coords, calls the CallbackFunction with the {{cDispenserEntity}} parameter representing the dispenser. The CallbackFunction has the following signature:
function Callback({{cDispenserEntity|DispenserEntity}}, [CallbackData])
The function returns false if there is no dispenser, or if there is, it returns the bool value that the callback has returned." }, diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua index de42f66df..294d47295 100644 --- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua +++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua @@ -50,6 +50,32 @@ return }, }, + cBeaconEntity = + { + Desc = [[ + A beacon entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a beacon + in the world. + ]], + + Inherits = "cBlockEntityWithItems", + + Functions = + { + IsActive = { Params = "", Return = "bool", Notes = "Is the beacon active?" }, + GetBeaconLevel = { Params = "", Return = "number", Notes = "Returns the beacon level. (0 - 4)" }, + GetPrimaryPotion = { Params = "", Return = "EffectType", Notes = "Returns the primary potion." }, + GetSecondaryPotion = { Params = "", Return = "EffectType", Notes = "Returns the secondary potion." }, + SelectPrimaryPotion = { Params = "EffectType", Return = "bool", Notes = "Select the primary potion. Returns false when the potion is invalid." }, + SelectSecondaryPotion = { Params = "EffectType", Return = "bool", Notes = "Select the secondary potion. Returns false when the potion is invalid." }, + CalculatePyramidLevel = { Params = "", Return = "number", Notes = "Calculate the amount of layers the pyramid below the beacon has." }, + IsBeaconBlocked = { Params = "", Return = "bool", Notes = "Is the beacon blocked by non-transparent blocks that are higher than the beacon?" }, + UpdateBeacon = { Params = "", Return = "", Notes = "Update the beacon." }, + GiveEffects = { Params = "", Return = "", Notes = "Give the near-players the effects." }, + IsMineralBlock = { Params = "BLOCKTYPE", Return = "bool", Notes = "Returns true if the block is a diamond block, a golden block, an iron block or an emerald block." }, + IsValidPotion = { Params = "EffectType", Return = "bool", Notes = "Returns true if the potion can be used." }, + }, + }, + cChestEntity = { Desc = [[ From 7821326370385ddcfe2ac28034727d02abf104da Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Wed, 30 Jul 2014 22:43:59 +0200 Subject: [PATCH 046/751] Suggestions --- src/Generating/Trees.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 4786cad5a..32594d0b4 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -412,10 +412,10 @@ void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noi void GetDarkoakTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { - // Calculate a height + // Pick a height int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 11) % 4; - // Creat the trunk + // Create the trunk for (int i = 0; i < Height; i++) { a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_NEW_LOG, E_META_NEW_LOG_DARK_OAK_WOOD)); From dcd226d9040409dec41c8f1f8909262946308ab0 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 22:50:34 +0200 Subject: [PATCH 047/751] Added beacon load/save. --- src/BlockEntities/BeaconEntity.h | 3 ++ src/WorldStorage/NBTChunkSerializer.cpp | 19 ++++++++++ src/WorldStorage/NBTChunkSerializer.h | 2 + src/WorldStorage/WSSAnvil.cpp | 50 ++++++++++++++++++++++++- src/WorldStorage/WSSAnvil.h | 1 + 5 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 07b2b85dc..59a4bdbd9 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -41,6 +41,9 @@ public: virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual void UsedBy(cPlayer * a_Player) override; + /** Modify the beacon level. (It is needed to load the beacon corectly) */ + void SetBeaconLevel(char a_Level) { m_BeaconLevel = a_Level; } + // tolua_begin /** Is the beacon active? */ diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 4857da1b6..63387c33d 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -10,6 +10,7 @@ #include "../StringCompression.h" #include "FastNBT.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -176,6 +177,23 @@ void cNBTChunkSerializer::AddBasicTileEntity(cBlockEntity * a_Entity, const char +void cNBTChunkSerializer::AddBeaconEntity(cBeaconEntity * a_Entity) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_Entity, "Beacon"); + m_Writer.AddInt("Levels", a_Entity->GetBeaconLevel()); + m_Writer.AddInt("Primary", (int)a_Entity->GetPrimaryPotion()); + m_Writer.AddInt("Secondary", (int)a_Entity->GetSecondaryPotion()); + m_Writer.BeginList("Items", TAG_Compound); + AddItemGrid(a_Entity->GetContents()); + m_Writer.EndList(); + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity, BLOCKTYPE a_ChestType) { m_Writer.BeginCompound(""); @@ -825,6 +843,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { + case E_BLOCK_BEACON: AddBeaconEntity ((cBeaconEntity *) a_Entity); break; case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break; case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break; case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 710a06a70..4c229a65c 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -20,6 +20,7 @@ class cFastNBTWriter; class cEntity; class cBlockEntity; class cBoat; +class cBeaconEntity; class cChestEntity; class cCommandBlockEntity; class cDispenserEntity; @@ -93,6 +94,7 @@ protected: // Block entities: void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); + void AddBeaconEntity (cBeaconEntity * a_Entity); void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType); void AddDispenserEntity(cDispenserEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 71ff3ef99..5a1972fd4 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -16,6 +16,7 @@ #include "../StringCompression.h" #include "../SetChunkData.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -582,7 +583,11 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { continue; } - if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0) + 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); } @@ -746,6 +751,49 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a +void cWSSAnvil::LoadBeaconFromNBT(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 Beacon(new cBeaconEntity(x, y, z, m_World)); + + int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels"); + if (CurrentLine >= 0) + { + Beacon->SetBeaconLevel((char)a_NBT.GetInt(CurrentLine)); + } + + CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Primary"); + if (CurrentLine >= 0) + { + Beacon->SelectPrimaryPotion((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + } + + CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Secondary"); + if (CurrentLine >= 0) + { + Beacon->SelectSecondaryPotion((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + } + + // We are better than mojang, we load/save the beacon inventory! + int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); + if ((Items >= 0) && (a_NBT.GetType(Items) == TAG_List)) + { + LoadItemGridFromNBT(Beacon->GetContents(), a_NBT, Items); + } + + a_BlockEntities.push_back(Beacon.release()); +} + + + + + void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType) { ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 9f8714404..f8eeb8247 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -133,6 +133,7 @@ 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); From e6ca5a5ece61d8a4dd69b877a91f567edf2a3f63 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 30 Jul 2014 22:54:19 +0200 Subject: [PATCH 048/751] Added window update. --- src/BlockEntities/BeaconEntity.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 38b710181..30d927663 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -127,6 +127,12 @@ bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion) } m_PrimaryPotion = a_Potion; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(1, m_PrimaryPotion); + } return true; } @@ -142,6 +148,12 @@ bool cBeaconEntity::SelectSecondaryPotion(cEntityEffect::eType a_Potion) } m_SecondaryPotion = a_Potion; + + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(2, m_SecondaryPotion); + } return true; } @@ -189,6 +201,8 @@ bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType) void cBeaconEntity::UpdateBeacon(void) { + int OldBeaconLevel = m_BeaconLevel; + if (IsBeaconBlocked()) { m_IsActive = false; @@ -200,6 +214,15 @@ void cBeaconEntity::UpdateBeacon(void) m_IsActive = (m_BeaconLevel > 0); } + if (m_BeaconLevel != OldBeaconLevel) + { + // Send window update: + if (GetWindow() != NULL) + { + GetWindow()->SetProperty(0, m_BeaconLevel); + } + } + // TODO: Add achievement } From 8b519bf6e20a987c9544ef11f0df6467831cc069 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 31 Jul 2014 10:02:50 +0200 Subject: [PATCH 049/751] MojangAPI: Added a UseCachedOnly param to GetUUIDsFromPlayerNames(). --- MCServer/Plugins/APIDump/APIDesc.lua | 2 +- MCServer/Plugins/Debuggers/Debuggers.lua | 32 +++++++++++++++++++++++- src/Bindings/ManualBindings.cpp | 19 ++++++++++---- src/Protocol/MojangAPI.cpp | 7 ++++-- src/Protocol/MojangAPI.h | 6 +++-- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 2a8ae90f9..9d0e90999 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1630,7 +1630,7 @@ a_Player:OpenWindow(Window); Functions = { AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp." }, - GetUUIDsFromPlayerNames = { Params = "PlayerNames", Return = "table", Notes = "Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. Queries the Mojang servers for the results. WARNING: Do NOT use this function while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, + GetUUIDsFromPlayerNames = { Params = "PlayerNames, [UseOnlyCached]", Return = "table", Notes = "Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. If UseOnlyCached is false (the default), queries the Mojang servers for the results that are not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, }, diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 575d696cb..075cfa40c 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -307,8 +307,38 @@ function TestUUIDFromName() "aloe_vera", } UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(ValidPlayerNames); + + -- Log the results: + for _, name in ipairs(ValidPlayerNames) do + local UUID = UUIDs[name] + if (UUID == nil) then + LOG(" UUID(" .. name .. ") not found.") + else + LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"") + end + end + + -- Test yet again, cache-only: + LOG("Testing once more, cache only...") + local PlayerNames3 = + { + "xoft", + "aloe_vera", + "notch", -- Valid player name, but not cached (most likely :) + } + UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(PlayerNames3, true) - LOG("UUID-from-Name resolution test finished.") + -- Log the results: + for _, name in ipairs(PlayerNames3) do + local UUID = UUIDs[name] + if (UUID == nil) then + LOG(" UUID(" .. name .. ") not found.") + else + LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"") + end + end + + LOG("UUID-from-Name resolution tests finished.") end diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index b1d302560..038173c99 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2163,7 +2163,7 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) if ( !S.CheckParamUserTable(1, "cMojangAPI") || !S.CheckParamTable(2) || - !S.CheckParamEnd(3) + !S.CheckParamEnd(4) ) { return 0; @@ -2177,19 +2177,27 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) { lua_rawgeti(L, 2, i); AString Name; - S.GetStackValue(3, Name); + S.GetStackValue(-1, Name); if (!Name.empty()) { PlayerNames.push_back(Name); } lua_pop(L, 1); } + + // If the UseOnlyCached param was given, read it; default to false + bool ShouldUseCacheOnly = false; + if (lua_gettop(L) == 3) + { + ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0); + lua_pop(L, 1); + } // Push the output table onto the stack: - lua_newtable(L); // stack index 3 + lua_newtable(L); // Get the UUIDs: - AStringVector UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames); + AStringVector UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames, ShouldUseCacheOnly); if (UUIDs.size() != PlayerNames.size()) { // A hard error has occured while processing the request, no UUIDs were returned. Return an empty table: @@ -2197,7 +2205,8 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) } // Convert to output table, PlayerName -> UUID: - for (int i = 0; i < NumNames; i++) + size_t len = UUIDs.size(); + for (size_t i = 0; i < len; i++) { if (UUIDs[i].empty()) { diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 5fbc5b476..71a5e53de 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -129,7 +129,7 @@ void cMojangAPI::Start(cIniFile & a_SettingsIni) -AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames) +AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached) { // Convert all playernames to lowercase: AStringVector PlayerNames; @@ -140,7 +140,10 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player } // for itr - a_PlayerNames[] // Request the cache to populate any names not yet contained: - CacheNamesToUUIDs(PlayerNames); + if (!a_UseOnlyCached) + { + CacheNamesToUUIDs(PlayerNames); + } // Retrieve from cache: size_t idx = 0; diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index c99f940ad..ac8995bb5 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -50,8 +50,10 @@ public: /** Converts the player names into UUIDs. a_PlayerName[idx] will be converted to UUID and returned as idx-th value The UUID will be empty on error. - Blocking operation, do not use in world-tick thread! */ - AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName); + If a_UseOnlyCached is true, only the cached values are returned. + If a_UseOnlyCached is false, the names not found in the cache are looked up online, which is a blocking + operation, do not use this in world-tick thread! */ + AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName, bool a_UseOnlyCached = false); // tolua_begin From 556fc908aedcc36388e9d859487b140045e5e33e Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 12:13:11 +0200 Subject: [PATCH 050/751] Renamed functions and added beacon json saving. --- src/BlockEntities/BeaconEntity.cpp | 78 ++++++++++++------------- src/BlockEntities/BeaconEntity.h | 12 ++-- src/ClientHandle.cpp | 24 ++++---- src/Protocol/Protocol17x.cpp | 4 +- src/UI/Window.cpp | 4 +- src/WorldStorage/NBTChunkSerializer.cpp | 4 +- src/WorldStorage/WSSAnvil.cpp | 4 +- src/WorldStorage/WSSCompact.cpp | 20 +++++++ 8 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 30d927663..c94783ba8 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -13,8 +13,8 @@ cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * : super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, 1, 1, a_World) , m_IsActive(false) , m_BeaconLevel(0) - , m_PrimaryPotion(cEntityEffect::effNoEffect) - , m_SecondaryPotion(cEntityEffect::effNoEffect) + , m_PrimaryEffect(cEntityEffect::effNoEffect) + , m_SecondaryEffect(cEntityEffect::effNoEffect) { UpdateBeacon(); } @@ -62,9 +62,9 @@ char cBeaconEntity::CalculatePyramidLevel(void) -bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel) +bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel) { - if (a_Potion == cEntityEffect::effNoEffect) + if (a_Effect == cEntityEffect::effNoEffect) { return true; } @@ -74,7 +74,7 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe case 4: { // Beacon level 4 - if (a_Potion == cEntityEffect::effRegeneration) + if (a_Effect == cEntityEffect::effRegeneration) { return true; } @@ -82,7 +82,7 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe case 3: { // Beacon level 3 - if (a_Potion == cEntityEffect::effStrength) + if (a_Effect == cEntityEffect::effStrength) { return true; } @@ -90,7 +90,7 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe case 2: { // Beacon level 2 - switch (a_Potion) + switch (a_Effect) { case cEntityEffect::effResistance: case cEntityEffect::effJumpBoost: @@ -102,7 +102,7 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe case 1: { // Beacon level 1 - switch (a_Potion) + switch (a_Effect) { case cEntityEffect::effSpeed: case cEntityEffect::effHaste: @@ -119,19 +119,19 @@ bool cBeaconEntity::IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLe -bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion) +bool cBeaconEntity::SelectPrimaryEffect(cEntityEffect::eType a_Effect) { - if (!IsValidPotion(a_Potion, m_BeaconLevel)) + if (!IsValidEffect(a_Effect, m_BeaconLevel)) { return false; } - m_PrimaryPotion = a_Potion; + m_PrimaryEffect = a_Effect; // Send window update: if (GetWindow() != NULL) { - GetWindow()->SetProperty(1, m_PrimaryPotion); + GetWindow()->SetProperty(1, m_PrimaryEffect); } return true; } @@ -140,19 +140,19 @@ bool cBeaconEntity::SelectPrimaryPotion(cEntityEffect::eType a_Potion) -bool cBeaconEntity::SelectSecondaryPotion(cEntityEffect::eType a_Potion) +bool cBeaconEntity::SelectSecondaryEffect(cEntityEffect::eType a_Effect) { - if (!IsValidPotion(a_Potion, m_BeaconLevel)) + if (!IsValidEffect(a_Effect, m_BeaconLevel)) { return false; } - m_SecondaryPotion = a_Potion; + m_SecondaryEffect = a_Effect; // Send window update: if (GetWindow() != NULL) { - GetWindow()->SetProperty(2, m_SecondaryPotion); + GetWindow()->SetProperty(2, m_SecondaryEffect); } return true; } @@ -163,17 +163,15 @@ bool cBeaconEntity::SelectSecondaryPotion(cEntityEffect::eType a_Potion) bool cBeaconEntity::IsBeaconBlocked(void) { - bool IsBlocked = false; for (int Y = m_PosY; Y < cChunkDef::Height; ++Y) { BLOCKTYPE Block = m_World->GetBlock(m_PosX, Y, m_PosZ); if (!cBlockInfo::IsTransparent(Block)) { - IsBlocked = true; - break; + return true; } } - return IsBlocked; + return false; } @@ -239,22 +237,22 @@ void cBeaconEntity::GiveEffects(void) int Radius = m_BeaconLevel * 10 + 10; short EffectLevel = 0; - if ((m_BeaconLevel >= 4) && (m_PrimaryPotion == m_SecondaryPotion)) + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect == m_SecondaryEffect)) { EffectLevel = 1; } - cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect; - if ((m_BeaconLevel >= 4) && (m_PrimaryPotion != m_SecondaryPotion) && (m_SecondaryPotion > 0)) + cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; + if ((m_BeaconLevel >= 4) && (m_PrimaryEffect != m_SecondaryEffect) && (m_SecondaryEffect > 0)) { - SecondaryPotion = m_SecondaryPotion; + SecondaryEffect = m_SecondaryEffect; } class cPlayerCallback : public cPlayerListCallback { int m_Radius; int m_PosX, m_PosY, m_PosZ; - cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion; + cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect; short m_EffectLevel; virtual bool Item(cPlayer * a_Player) @@ -269,28 +267,28 @@ void cBeaconEntity::GiveEffects(void) Vector3d BeaconPosition = Vector3d(m_PosX, m_PosY, m_PosZ); if ((PlayerPosition - BeaconPosition).Length() <= m_Radius) { - a_Player->AddEntityEffect(m_PrimaryPotion, 180, m_EffectLevel); + a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel); - if (m_SecondaryPotion != cEntityEffect::effNoEffect) + if (m_SecondaryEffect != cEntityEffect::effNoEffect) { - a_Player->AddEntityEffect(m_SecondaryPotion, 180, 0); + a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0); } } return false; } public: - cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryPotion, cEntityEffect::eType a_SecondaryPotion, short a_EffectLevel) + cPlayerCallback(int a_Radius, int a_PosX, int a_PosY, int a_PosZ, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel) : m_Radius(a_Radius) , m_PosX(a_PosX) , m_PosY(a_PosY) , m_PosZ(a_PosZ) - , m_PrimaryPotion(a_PrimaryPotion) - , m_SecondaryPotion(a_SecondaryPotion) + , m_PrimaryEffect(a_PrimaryEffect) + , m_SecondaryEffect(a_SecondaryEffect) , m_EffectLevel(a_EffectLevel) {}; - } PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryPotion, SecondaryPotion, EffectLevel); + } PlayerCallback(Radius, m_PosX, m_PosY, m_PosZ, m_PrimaryEffect, SecondaryEffect, EffectLevel); GetWorld()->ForEachPlayer(PlayerCallback); } @@ -353,17 +351,17 @@ bool cBeaconEntity::LoadFromJson(const Json::Value & a_Value) } m_BeaconLevel = (char)a_Value.get("Level", 0).asInt(); - int PrimaryPotion = a_Value.get("PrimaryPotion", 0).asInt(); - int SecondaryPotion = a_Value.get("SecondaryPotion", 0).asInt(); + int PrimaryEffect = a_Value.get("PrimaryEffect", 0).asInt(); + int SecondaryEffect = a_Value.get("SecondaryEffect", 0).asInt(); - if ((PrimaryPotion >= 0) && (PrimaryPotion <= (int)cEntityEffect::effSaturation)) + if ((PrimaryEffect >= 0) && (PrimaryEffect <= (int)cEntityEffect::effSaturation)) { - m_PrimaryPotion = (cEntityEffect::eType)PrimaryPotion; + m_PrimaryEffect = (cEntityEffect::eType)PrimaryEffect; } - if ((SecondaryPotion >= 0) && (SecondaryPotion <= (int)cEntityEffect::effSaturation)) + if ((SecondaryEffect >= 0) && (SecondaryEffect <= (int)cEntityEffect::effSaturation)) { - m_SecondaryPotion = (cEntityEffect::eType)SecondaryPotion; + m_SecondaryEffect = (cEntityEffect::eType)SecondaryEffect; } return true; @@ -390,8 +388,8 @@ void cBeaconEntity::SaveToJson(Json::Value& a_Value) a_Value["Slots"] = AllSlots; a_Value["Level"] = m_BeaconLevel; - a_Value["PrimaryPotion"] = (int)m_PrimaryPotion; - a_Value["SecondaryPotion"] = (int)m_SecondaryPotion; + a_Value["PrimaryEffect"] = (int)m_PrimaryEffect; + a_Value["SecondaryEffect"] = (int)m_SecondaryEffect; } diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 59a4bdbd9..5cf8da24e 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -52,14 +52,14 @@ public: /** Returns the beacon level. (0 - 4) */ char GetBeaconLevel(void) const { return m_BeaconLevel; } - cEntityEffect::eType GetPrimaryPotion(void) const { return m_PrimaryPotion; } - cEntityEffect::eType GetSecondaryPotion(void) const { return m_SecondaryPotion; } + cEntityEffect::eType GetPrimaryEffect(void) const { return m_PrimaryEffect; } + cEntityEffect::eType GetSecondaryEffect(void) const { return m_SecondaryEffect; } /** Select the primary potion. Returns false when the potion is invalid.*/ - bool SelectPrimaryPotion(cEntityEffect::eType a_Potion); + bool SelectPrimaryEffect(cEntityEffect::eType a_Effect); /** Select the secondary potion. Returns false when the potion is invalid. */ - bool SelectSecondaryPotion(cEntityEffect::eType a_Potion); + bool SelectSecondaryEffect(cEntityEffect::eType a_Effect); /** Calculate the amount of layers the pyramid below the beacon has. */ char CalculatePyramidLevel(void); @@ -77,7 +77,7 @@ public: static bool IsMineralBlock(BLOCKTYPE a_BlockType); /** Returns true if the potion can be used. */ - static bool IsValidPotion(cEntityEffect::eType a_Potion, char a_BeaconLevel); + static bool IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel); // tolua_end @@ -85,7 +85,7 @@ protected: bool m_IsActive; char m_BeaconLevel; - cEntityEffect::eType m_PrimaryPotion, m_SecondaryPotion; + cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect; } ; // tolua_export diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 849de2ce1..e833f338a 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -7,6 +7,7 @@ #include "Bindings/PluginManager.h" #include "Entities/Player.h" #include "Inventory.h" +#include "BlockEntities/BeaconEntity.h" #include "BlockEntities/ChestEntity.h" #include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" @@ -31,7 +32,6 @@ #include "Items/ItemSword.h" #include "polarssl/md5.h" -#include "BlockEntities/BeaconEntity.h" @@ -775,25 +775,25 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) cByteBuffer Buffer(a_Length); Buffer.Write(a_Data, a_Length); - int PrimaryPotionID, SecondaryPotionID; - Buffer.ReadBEInt(PrimaryPotionID); - Buffer.ReadBEInt(SecondaryPotionID); + int PrimaryEffectID, SecondaryEffectID; + Buffer.ReadBEInt(PrimaryEffectID); + Buffer.ReadBEInt(SecondaryEffectID); - cEntityEffect::eType PrimaryPotion = cEntityEffect::effNoEffect; - if ((PrimaryPotionID >= 0) && (PrimaryPotionID <= (int)cEntityEffect::effSaturation)) + cEntityEffect::eType PrimaryEffect = cEntityEffect::effNoEffect; + if ((PrimaryEffectID >= 0) && (PrimaryEffectID <= (int)cEntityEffect::effSaturation)) { - PrimaryPotion = (cEntityEffect::eType)PrimaryPotionID; + PrimaryEffect = (cEntityEffect::eType)PrimaryEffectID; } - cEntityEffect::eType SecondaryPotion = cEntityEffect::effNoEffect; - if ((SecondaryPotionID >= 0) && (SecondaryPotionID <= (int)cEntityEffect::effSaturation)) + cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect; + if ((SecondaryEffectID >= 0) && (SecondaryEffectID <= (int)cEntityEffect::effSaturation)) { - SecondaryPotion = (cEntityEffect::eType)SecondaryPotionID; + SecondaryEffect = (cEntityEffect::eType)SecondaryEffectID; } Window->SetSlot(*m_Player, 0, cItem()); - BeaconWindow->GetBeaconEntity()->SelectPrimaryPotion(PrimaryPotion); - BeaconWindow->GetBeaconEntity()->SelectSecondaryPotion(SecondaryPotion); + BeaconWindow->GetBeaconEntity()->SelectPrimaryEffect(PrimaryEffect); + BeaconWindow->GetBeaconEntity()->SelectSecondaryEffect(SecondaryEffect); } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 8a68edd1f..8e31e211c 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -2590,8 +2590,8 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddInt("x", BeaconEntity.GetPosX()); Writer.AddInt("y", BeaconEntity.GetPosY()); Writer.AddInt("z", BeaconEntity.GetPosZ()); - Writer.AddInt("Primary", BeaconEntity.GetPrimaryPotion()); - Writer.AddInt("Secondary", BeaconEntity.GetSecondaryPotion()); + Writer.AddInt("Primary", BeaconEntity.GetPrimaryEffect()); + Writer.AddInt("Secondary", BeaconEntity.GetSecondaryEffect()); Writer.AddInt("Levels", BeaconEntity.GetBeaconLevel()); Writer.AddString("id", "Beacon"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index aa129bfe8..8f4913030 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -863,8 +863,8 @@ void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player) super::OpenedByPlayer(a_Player); a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel()); - a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryPotion()); - a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryPotion()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect()); + a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect()); } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 63387c33d..601cd8833 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -182,8 +182,8 @@ void cNBTChunkSerializer::AddBeaconEntity(cBeaconEntity * a_Entity) m_Writer.BeginCompound(""); AddBasicTileEntity(a_Entity, "Beacon"); m_Writer.AddInt("Levels", a_Entity->GetBeaconLevel()); - m_Writer.AddInt("Primary", (int)a_Entity->GetPrimaryPotion()); - m_Writer.AddInt("Secondary", (int)a_Entity->GetSecondaryPotion()); + m_Writer.AddInt("Primary", (int)a_Entity->GetPrimaryEffect()); + m_Writer.AddInt("Secondary", (int)a_Entity->GetSecondaryEffect()); m_Writer.BeginList("Items", TAG_Compound); AddItemGrid(a_Entity->GetContents()); m_Writer.EndList(); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 5a1972fd4..555ef410d 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -771,13 +771,13 @@ void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cPar CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Primary"); if (CurrentLine >= 0) { - Beacon->SelectPrimaryPotion((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + Beacon->SelectPrimaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); } CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Secondary"); if (CurrentLine >= 0) { - Beacon->SelectSecondaryPotion((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + Beacon->SelectSecondaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); } // We are better than mojang, we load/save the beacon inventory! diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index ee47047a0..58f9e3cab 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -9,6 +9,7 @@ #include "zlib/zlib.h" #include "json/json.h" #include "../StringCompression.h" +#include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" @@ -75,6 +76,7 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity) const char * SaveInto = NULL; switch (a_BlockEntity->GetBlockType()) { + case E_BLOCK_BEACON: SaveInto = "Beacons"; break; case E_BLOCK_CHEST: SaveInto = "Chests"; break; case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break; case E_BLOCK_DROPPER: SaveInto = "Droppers"; break; @@ -268,6 +270,24 @@ bool cWSSCompact::EraseChunkData(const cChunkCoords & a_Chunk) void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World) { + // Load beacon: + Json::Value AllBeacons = a_Value.get("Beacons", Json::nullValue); + if (!AllBeacons.empty()) + { + for (Json::Value::iterator itr = AllBeacons.begin(); itr != AllBeacons.end(); ++itr) + { + std::auto_ptr BeaconEntity(new cBeaconEntity(0, 0, 0, a_World)); + if (!BeaconEntity->LoadFromJson(*itr)) + { + LOGWARNING("ERROR READING BEACON FROM JSON!"); + } + else + { + a_BlockEntities.push_back(BeaconEntity.release()); + } + } // for itr - AllBeacons[] + } + // Load chests: Json::Value AllChests = a_Value.get("Chests", Json::nullValue); if (!AllChests.empty()) From c49d4fd215170da29b5c285cc6a344ec102764c6 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 12:15:18 +0200 Subject: [PATCH 051/751] Updated documentation. --- MCServer/Plugins/APIDump/Classes/BlockEntities.lua | 10 +++++----- src/BlockEntities/BeaconEntity.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua index 294d47295..524087a8e 100644 --- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua +++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua @@ -63,16 +63,16 @@ return { IsActive = { Params = "", Return = "bool", Notes = "Is the beacon active?" }, GetBeaconLevel = { Params = "", Return = "number", Notes = "Returns the beacon level. (0 - 4)" }, - GetPrimaryPotion = { Params = "", Return = "EffectType", Notes = "Returns the primary potion." }, - GetSecondaryPotion = { Params = "", Return = "EffectType", Notes = "Returns the secondary potion." }, - SelectPrimaryPotion = { Params = "EffectType", Return = "bool", Notes = "Select the primary potion. Returns false when the potion is invalid." }, - SelectSecondaryPotion = { Params = "EffectType", Return = "bool", Notes = "Select the secondary potion. Returns false when the potion is invalid." }, + GetPrimaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the primary potion." }, + GetSecondaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the secondary potion." }, + SelectPrimaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the primary effect. Returns false when the effect is invalid." }, + SelectSecondaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the secondary effect. Returns false when the effect is invalid." }, CalculatePyramidLevel = { Params = "", Return = "number", Notes = "Calculate the amount of layers the pyramid below the beacon has." }, IsBeaconBlocked = { Params = "", Return = "bool", Notes = "Is the beacon blocked by non-transparent blocks that are higher than the beacon?" }, UpdateBeacon = { Params = "", Return = "", Notes = "Update the beacon." }, GiveEffects = { Params = "", Return = "", Notes = "Give the near-players the effects." }, IsMineralBlock = { Params = "BLOCKTYPE", Return = "bool", Notes = "Returns true if the block is a diamond block, a golden block, an iron block or an emerald block." }, - IsValidPotion = { Params = "EffectType", Return = "bool", Notes = "Returns true if the potion can be used." }, + IsValidEffect = { Params = "EffectType", Return = "bool", Notes = "Returns true if the effect can be used." }, }, }, diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index 5cf8da24e..cc8ee8ad2 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -55,10 +55,10 @@ public: cEntityEffect::eType GetPrimaryEffect(void) const { return m_PrimaryEffect; } cEntityEffect::eType GetSecondaryEffect(void) const { return m_SecondaryEffect; } - /** Select the primary potion. Returns false when the potion is invalid.*/ + /** Select the primary effect. Returns false when the effect is invalid.*/ bool SelectPrimaryEffect(cEntityEffect::eType a_Effect); - /** Select the secondary potion. Returns false when the potion is invalid. */ + /** Select the secondary effect. Returns false when the effect is invalid. */ bool SelectSecondaryEffect(cEntityEffect::eType a_Effect); /** Calculate the amount of layers the pyramid below the beacon has. */ @@ -76,7 +76,7 @@ public: /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ static bool IsMineralBlock(BLOCKTYPE a_BlockType); - /** Returns true if the potion can be used. */ + /** Returns true if the effect can be used. */ static bool IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel); // tolua_end From 59adf113f0ba6414edf061fc4ffbf2bb2b904883 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 31 Jul 2014 17:22:48 +0200 Subject: [PATCH 052/751] MojangAPI: Moved the settings to a separate ini section. --- 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 71a5e53de..fa99d63fd 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -120,8 +120,8 @@ cMojangAPI::~cMojangAPI() void cMojangAPI::Start(cIniFile & a_SettingsIni) { - m_NameToUUIDServer = a_SettingsIni.GetValueSet("Authentication", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); - m_NameToUUIDAddress = a_SettingsIni.GetValueSet("Authentication", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); + m_NameToUUIDServer = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); + m_NameToUUIDAddress = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); LoadCachesFromDisk(); } From 6b1f7e7a45ebc04f39bb54edc85fbe9c9d0659e7 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 18:15:39 +0200 Subject: [PATCH 053/751] Renamed "select..." methods to "set..." and better IsValidEffect() function. --- src/BlockEntities/BeaconEntity.cpp | 58 ++++++------------------------ src/BlockEntities/BeaconEntity.h | 8 ++--- src/ClientHandle.cpp | 4 +-- src/WorldStorage/WSSAnvil.cpp | 4 +-- 4 files changed, 19 insertions(+), 55 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index c94783ba8..55c5ccb7f 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -64,54 +64,18 @@ char cBeaconEntity::CalculatePyramidLevel(void) bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLevel) { - if (a_Effect == cEntityEffect::effNoEffect) + switch (a_Effect) { - return true; + case cEntityEffect::effRegeneration: return (a_BeaconLevel >= 4); + case cEntityEffect::effStrength: return (a_BeaconLevel >= 3); + case cEntityEffect::effResistance: return (a_BeaconLevel >= 2); + case cEntityEffect::effJumpBoost: return (a_BeaconLevel >= 2); + case cEntityEffect::effSpeed: return (a_BeaconLevel >= 1); + case cEntityEffect::effHaste: return (a_BeaconLevel >= 1); + case cEntityEffect::effNoEffect: return true; } - switch (a_BeaconLevel) - { - case 4: - { - // Beacon level 4 - if (a_Effect == cEntityEffect::effRegeneration) - { - return true; - } - } - case 3: - { - // Beacon level 3 - if (a_Effect == cEntityEffect::effStrength) - { - return true; - } - } - case 2: - { - // Beacon level 2 - switch (a_Effect) - { - case cEntityEffect::effResistance: - case cEntityEffect::effJumpBoost: - { - return true; - } - } - } - case 1: - { - // Beacon level 1 - switch (a_Effect) - { - case cEntityEffect::effSpeed: - case cEntityEffect::effHaste: - { - return true; - } - } - } - } + LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, (int)a_Effect); return false; } @@ -119,7 +83,7 @@ bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLe -bool cBeaconEntity::SelectPrimaryEffect(cEntityEffect::eType a_Effect) +bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect) { if (!IsValidEffect(a_Effect, m_BeaconLevel)) { @@ -140,7 +104,7 @@ bool cBeaconEntity::SelectPrimaryEffect(cEntityEffect::eType a_Effect) -bool cBeaconEntity::SelectSecondaryEffect(cEntityEffect::eType a_Effect) +bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect) { if (!IsValidEffect(a_Effect, m_BeaconLevel)) { diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h index cc8ee8ad2..0d7150aef 100644 --- a/src/BlockEntities/BeaconEntity.h +++ b/src/BlockEntities/BeaconEntity.h @@ -55,11 +55,11 @@ public: cEntityEffect::eType GetPrimaryEffect(void) const { return m_PrimaryEffect; } cEntityEffect::eType GetSecondaryEffect(void) const { return m_SecondaryEffect; } - /** Select the primary effect. Returns false when the effect is invalid.*/ - bool SelectPrimaryEffect(cEntityEffect::eType a_Effect); + /** Sets the primary effect. Returns false when the effect is invalid. */ + bool SetPrimaryEffect(cEntityEffect::eType a_Effect); - /** Select the secondary effect. Returns false when the effect is invalid. */ - bool SelectSecondaryEffect(cEntityEffect::eType a_Effect); + /** Sets the secondary effect. Returns false when the effect is invalid. */ + bool SetSecondaryEffect(cEntityEffect::eType a_Effect); /** Calculate the amount of layers the pyramid below the beacon has. */ char CalculatePyramidLevel(void); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index e833f338a..3ce506e1e 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -792,8 +792,8 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) } Window->SetSlot(*m_Player, 0, cItem()); - BeaconWindow->GetBeaconEntity()->SelectPrimaryEffect(PrimaryEffect); - BeaconWindow->GetBeaconEntity()->SelectSecondaryEffect(SecondaryEffect); + BeaconWindow->GetBeaconEntity()->SetPrimaryEffect(PrimaryEffect); + BeaconWindow->GetBeaconEntity()->SetSecondaryEffect(SecondaryEffect); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 555ef410d..d3a156ee1 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -771,13 +771,13 @@ void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cPar CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Primary"); if (CurrentLine >= 0) { - Beacon->SelectPrimaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + Beacon->SetPrimaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); } CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Secondary"); if (CurrentLine >= 0) { - Beacon->SelectSecondaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); + Beacon->SetSecondaryEffect((cEntityEffect::eType)a_NBT.GetInt(CurrentLine)); } // We are better than mojang, we load/save the beacon inventory! From c138d19c31ee85a38fe758bc2c69591bcfe42230 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 18:16:52 +0200 Subject: [PATCH 054/751] Updated documentation again. --- MCServer/Plugins/APIDump/Classes/BlockEntities.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua index 524087a8e..90ebf12e6 100644 --- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua +++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua @@ -63,10 +63,10 @@ return { IsActive = { Params = "", Return = "bool", Notes = "Is the beacon active?" }, GetBeaconLevel = { Params = "", Return = "number", Notes = "Returns the beacon level. (0 - 4)" }, - GetPrimaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the primary potion." }, - GetSecondaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the secondary potion." }, - SelectPrimaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the primary effect. Returns false when the effect is invalid." }, - SelectSecondaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the secondary effect. Returns false when the effect is invalid." }, + GetPrimaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the primary effect." }, + GetSecondaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the secondary effect." }, + SetPrimaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the primary effect. Returns false when the effect is invalid." }, + SetSecondaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the secondary effect. Returns false when the effect is invalid." }, CalculatePyramidLevel = { Params = "", Return = "number", Notes = "Calculate the amount of layers the pyramid below the beacon has." }, IsBeaconBlocked = { Params = "", Return = "bool", Notes = "Is the beacon blocked by non-transparent blocks that are higher than the beacon?" }, UpdateBeacon = { Params = "", Return = "", Notes = "Update the beacon." }, From f47765dcbd8781d32f231d1ecdf4aac0b8c330ba Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 18:21:45 +0200 Subject: [PATCH 055/751] Added a default value to WaterSimulator, LavaSimulator and RedstoneSimulator. --- src/World.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index 348498693..b247a79bc 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3176,7 +3176,7 @@ void cWorld::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicke cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile) { - AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", ""); + AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "incremental"); if (SimulatorName.empty()) { @@ -3210,7 +3210,7 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c Printf(SimulatorNameKey, "%sSimulator", a_FluidName); AString SimulatorSectionName; Printf(SimulatorSectionName, "%sSimulator", a_FluidName); - AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, ""); + AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "Vanilla"); if (SimulatorName.empty()) { LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Vanilla\".", SimulatorNameKey.c_str(), GetIniFileName().c_str()); From bffad5043619d143d595806122dc625746126ed8 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 18:41:48 +0200 Subject: [PATCH 056/751] Fixed water from ice and removed packed ice drop. --- src/Blocks/BlockIce.h | 14 ++++++++++++-- src/Items/ItemHandler.cpp | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index c50623594..c085e9290 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -24,9 +24,19 @@ public: } - virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override { - // TODO: Ice destroyed with air below it should turn into air instead of water + if (a_Player->IsGameModeCreative() || (a_BlockY <= 0)) + { + return; + } + + BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!cBlockInfo::IsSolid(BlockBelow) && !IsBlockLava(BlockBelow) && !IsBlockWater(BlockBelow)) + { + return; + } + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0); // This is called later than the real destroying of this ice block } diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index d36b5d663..acfd1e648 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -578,6 +578,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) case E_BLOCK_LAPIS_BLOCK: case E_BLOCK_SNOW: case E_BLOCK_VINES: + case E_BLOCK_PACKED_ICE: { return false; } From ffd6797fe106c805646e2acfe5320594cc59ece4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 31 Jul 2014 18:17:21 +0100 Subject: [PATCH 057/751] Comment suggestions --- src/Mobs/Enderman.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index f1f366d3b..a32e4e175 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -22,7 +22,7 @@ public: virtual bool Item(cPlayer * a_Player) override { - // Don't check players who are in creative gamemode. + // Don't check players who are in creative gamemode if (a_Player->IsGameModeCreative()) { return false; @@ -30,13 +30,13 @@ public: Vector3d Direction = m_EndermanPos - a_Player->GetPosition(); - // Don't check players who are more then 64 blocks away. + // Don't check players who are more then 64 blocks away if (Direction.SqrLength() > 64) { return false; } - // Don't check if the player has a pumpkin on his head. + // Don't check if the player has a pumpkin on his head if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN) { return false; @@ -46,9 +46,8 @@ public: Vector3d LookVector = a_Player->GetLookVector(); double dot = Direction.Dot(LookVector); - // 0.09 rad ~ 5 degrees. - // If the players crosshair is within 5 degrees of the endermen - // It counts as looking. + // 0.09 rad ~ 5 degrees + // If the player's crosshair is within 5 degrees of the enderman, it counts as looking if (dot > cos(0.09)) { return false; @@ -119,17 +118,17 @@ void cEnderman::CheckEventSeePlayer() int ChunkX, ChunkZ; cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); - // Check if the chunk the enderman is in is lit. + // Check if the chunk the enderman is in is lit if (!m_World->IsChunkLighted(ChunkX, ChunkZ)) { m_World->QueueLightChunk(ChunkX, ChunkZ); return; } - // Enderman only attack if the skylight is higher than 6 + // Enderman only attack if the skylight is higher than 7 if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) <= 7) { - // TODO: Teleport the enderman to a random spot. + // TODO: Teleport the enderman to a random spot return; } From ecb86935f87ce2b9f1ae4671d8a8b722c798b8a2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 31 Jul 2014 22:52:06 +0200 Subject: [PATCH 058/751] Fixed UUIDs handling in cPlayer. The loading expected dashed UUIDs, MCS uses short UUIDs throughout. --- src/Entities/Player.cpp | 13 ++++++++----- src/Entities/Player.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fcc8eb9a0..477334948 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1700,8 +1700,10 @@ bool cPlayer::LoadFromDisk(void) // Load from the offline UUID file, if allowed: AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); + const char * OfflineUsage = " (unused)"; if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) { + OfflineUsage = ""; if (LoadFromFile(GetUUIDFileName(OfflineUUID))) { return true; @@ -1724,8 +1726,8 @@ bool cPlayer::LoadFromDisk(void) } // None of the files loaded successfully - LOG("Player data file not found for %s (%s, offline %s), will be reset to defaults.", - GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str() + LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.", + GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage ); return false; } @@ -2212,12 +2214,13 @@ void cPlayer::Detach() AString cPlayer::GetUUIDFileName(const AString & a_UUID) { - ASSERT(a_UUID.size() == 36); + AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID); + ASSERT(UUID.length() == 36); AString res("players/"); - res.append(a_UUID, 0, 2); + res.append(UUID, 0, 2); res.push_back('/'); - res.append(a_UUID, 2, AString::npos); + res.append(UUID, 2, AString::npos); res.append(".json"); return res; } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 488884602..29bb4c39d 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -536,7 +536,7 @@ protected: */ bool m_bIsTeleporting; - /** The UUID of the player, as read from the ClientHandle. + /** The short UUID (no dashes) of the player, as read from the ClientHandle. If no ClientHandle is given, the UUID is initialized to empty. */ AString m_UUID; From 70fd7caf1f879b0588042d6542c27ef8f0909a43 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 31 Jul 2014 22:54:45 +0200 Subject: [PATCH 059/751] Removed trailing whitespace. --- 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 fa99d63fd..45baa5a4f 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -245,7 +245,7 @@ AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) return a_UUID; } - case 36: + case 36: { // Remove the dashes from the string: AString res; @@ -277,7 +277,7 @@ AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) return a_UUID; } - case 32: + case 32: { // Insert dashes at the proper positions: AString res; From 84462ba8b20c28136c6a7923323f7cde28a86d70 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 23:04:00 +0200 Subject: [PATCH 060/751] Fixed hunger bugs, Implemented golden apple, added jump statistic, added correct food effects. --- src/ClientHandle.cpp | 4 ++- src/Entities/EntityEffect.cpp | 2 +- src/Entities/Player.cpp | 53 ++++++++++++++++++++++---------- src/Entities/Player.h | 5 +-- src/Items/ItemFood.h | 54 +++++++++++++++++++++++++++----- src/Items/ItemGoldenApple.h | 58 +++++++++++++++++++++++++++++++++++ src/Items/ItemHandler.cpp | 33 +++++++++++++------- src/Items/ItemHandler.h | 16 +++++----- 8 files changed, 177 insertions(+), 48 deletions(-) create mode 100644 src/Items/ItemGoldenApple.h diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 30ec737be..bd76ef227 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -634,6 +634,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, if (!m_Player->IsSwimming()) { + m_Player->GetStatManager().AddValue(eStatistic::statJumps, 1); m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2); } } @@ -1067,6 +1068,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo return; } + m_Player->AddFoodExhaustion(0.025); ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ); // The ItemHandler is also responsible for spawning the pickups cChunkInterface ChunkInterface(World->GetChunkMap()); @@ -1212,7 +1214,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage))) { if ((m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && - ItemHandler->IsFood()) + ItemHandler->IsFood() && (Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE)) { // The player is satiated or in creative, and trying to eat return; diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index fdcbe822e..39314f256 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -309,7 +309,7 @@ void cEntityEffectHunger::OnTick(cPawn & a_Target) if (a_Target.IsPlayer()) { cPlayer & Target = (cPlayer &) a_Target; - Target.SetFoodExhaustionLevel(Target.GetFoodExhaustionLevel() + 0.025); // 0.5 per second = 0.025 per tick + Target.AddFoodExhaustion(0.025 * ((double)GetIntensity() + 1.0)); // 0.5 per second = 0.025 per tick } } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 603fc7937..c9d885b89 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -545,7 +545,7 @@ void cPlayer::SetFoodTickTimer(int a_FoodTickTimer) void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel) { - m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 4.0)); + m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 40.0)); } @@ -568,6 +568,18 @@ bool cPlayer::Feed(int a_Food, double a_Saturation) +void cPlayer::AddFoodExhaustion(double a_Exhaustion) +{ + if (!IsGameModeCreative()) + { + m_FoodExhaustionLevel = std::min(m_FoodExhaustionLevel + a_Exhaustion, 40.0); + } +} + + + + + void cPlayer::FoodPoison(int a_NumTicks) { AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1); @@ -1979,19 +1991,34 @@ void cPlayer::HandleFood(void) return; } + // Apply food exhaustion that has accumulated: + if (m_FoodExhaustionLevel > 4.0) + { + m_FoodExhaustionLevel -= 4.0; + + if (m_FoodSaturationLevel > 0.0) + { + m_FoodSaturationLevel = std::max(m_FoodSaturationLevel - 1.0, 0.0); + } + else + { + SetFoodLevel(m_FoodLevel - 1); + } + } + // Heal or damage, based on the food level, using the m_FoodTickTimer: - if ((m_FoodLevel > 17) || (m_FoodLevel <= 0)) + if ((m_FoodLevel >= 18) || (m_FoodLevel <= 0)) { m_FoodTickTimer++; if (m_FoodTickTimer >= 80) { m_FoodTickTimer = 0; - if ((m_FoodLevel > 17) && (GetHealth() < GetMaxHealth())) + if ((m_FoodLevel >= 18) && (GetHealth() < GetMaxHealth())) { // Regenerate health from food, incur 3 pts of food exhaustion: Heal(1); - m_FoodExhaustionLevel += 3.0; + AddFoodExhaustion(3.0); } else if ((m_FoodLevel <= 0) && (m_Health > 1)) { @@ -2000,20 +2027,9 @@ void cPlayer::HandleFood(void) } } } - - // Apply food exhaustion that has accumulated: - if (m_FoodExhaustionLevel >= 4.0) + else { - m_FoodExhaustionLevel -= 4.0; - - if (m_FoodSaturationLevel >= 1.0) - { - m_FoodSaturationLevel -= 1.0; - } - else - { - SetFoodLevel(m_FoodLevel - 1); - } + m_FoodTickTimer = 0; } } @@ -2088,14 +2104,17 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) else if (IsSubmerged()) { m_Stats.AddValue(statDistDove, Value); + AddFoodExhaustion(0.00015 * (double)Value); } else if (IsSwimming()) { m_Stats.AddValue(statDistSwum, Value); + AddFoodExhaustion(0.00015 * (double)Value); } else if (IsOnGround()) { m_Stats.AddValue(statDistWalked, Value); + AddFoodExhaustion((m_IsSprinting ? 0.001 : 0.0001) * (double)Value); } else { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 65c1e33a8..f188789b8 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -284,10 +284,7 @@ public: bool Feed(int a_Food, double a_Saturation); /** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */ - void AddFoodExhaustion(double a_Exhaustion) - { - m_FoodExhaustionLevel += a_Exhaustion; - } + void AddFoodExhaustion(double a_Exhaustion); /** Starts the food poisoning for the specified amount of ticks */ void FoodPoison(int a_NumTicks); diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h index ff1d7991b..98050cad8 100644 --- a/src/Items/ItemFood.h +++ b/src/Items/ItemFood.h @@ -33,29 +33,69 @@ public: case E_ITEM_BREAD: return FoodInfo(5, 6); // Carrots handled in ItemSeeds case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2); - case E_ITEM_COOKED_FISH: return FoodInfo(5, 6); + case E_ITEM_COOKED_FISH: return FoodInfo(5, 6); // TODO: Add other fish types case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8); case E_ITEM_COOKIE: return FoodInfo(2, 0.4); - case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6); + // Golden apple handled in ItemGoldenApple case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4); case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2); case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2); - case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2, 60); + case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2); // Potatoes handled in ItemSeeds case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8); case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8); - case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30); + case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2); case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2); case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8); case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4); - case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80); - case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100); + case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8); + case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2); case E_ITEM_STEAK: return FoodInfo(8, 12.8); } LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType); return FoodInfo(0, 0.f); } - + + virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance) override + { + switch (m_ItemType) + { + case E_ITEM_RAW_CHICKEN: + { + a_EffectType = cEntityEffect::effHunger; + a_EffectDurationTicks = 600; + a_EffectIntensity = 0; + a_Chance = 0.3f; + return true; + } + case E_ITEM_ROTTEN_FLESH: + { + a_EffectType = cEntityEffect::effHunger; + a_EffectDurationTicks = 600; + a_EffectIntensity = 0; + a_Chance = 0.8f; + return true; + } + case E_ITEM_SPIDER_EYE: + { + a_EffectType = cEntityEffect::effPoison; + a_EffectDurationTicks = 100; + a_EffectIntensity = 0; + a_Chance = 1.0f; + return true; + } + case E_ITEM_POISONOUS_POTATO: + { + a_EffectType = cEntityEffect::effPoison; + a_EffectDurationTicks = 100; + a_EffectIntensity = 0; + a_Chance = 0.6f; + return true; + } + } + return false; + } + }; diff --git a/src/Items/ItemGoldenApple.h b/src/Items/ItemGoldenApple.h new file mode 100644 index 000000000..4e1096e65 --- /dev/null +++ b/src/Items/ItemGoldenApple.h @@ -0,0 +1,58 @@ +#pragma once + +#include "ItemFood.h" + + + + + +class cItemGoldenAppleHandler : + public cItemFoodHandler +{ + typedef cItemFoodHandler super; + +public: + cItemGoldenAppleHandler() + : super(E_ITEM_GOLDEN_APPLE) + { + } + + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override + { + // Feed the player: + FoodInfo Info = GetFoodInfo(); + a_Player->Feed(Info.FoodLevel, Info.Saturation); + + // Add the effects: + a_Player->AddEntityEffect(cEntityEffect::effAbsorption, 2400, 0); + a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 100, 1); + + // When the apple is a 'notch apple', give extra effects: + if (a_Item->m_ItemDamage > 0) + { + a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 600, 4); + a_Player->AddEntityEffect(cEntityEffect::effResistance, 6000, 0); + a_Player->AddEntityEffect(cEntityEffect::effFireResistance, 6000, 0); + } + + return true; + } + + + virtual FoodInfo GetFoodInfo(void) override + { + return FoodInfo(4, 9.6); + } + + + virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance) override + { + return false; + } + +}; + + + + diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index d36b5d663..c7cc682ca 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -25,6 +25,7 @@ #include "ItemFishingRod.h" #include "ItemFlowerPot.h" #include "ItemFood.h" +#include "ItemGoldenApple.h" #include "ItemItemFrame.h" #include "ItemHoe.h" #include "ItemLeaves.h" @@ -106,7 +107,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_BED: return new cItemBedHandler(a_ItemType); case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType); case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); - case E_ITEM_BOW: return new cItemBowHandler; + case E_ITEM_BOW: return new cItemBowHandler(); case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); @@ -120,6 +121,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); + case E_ITEM_GOLDEN_APPLE: return new cItemGoldenAppleHandler(); case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); case E_ITEM_MAP: return new cItemMapHandler(); case E_ITEM_MILK: return new cItemMilkHandler(); @@ -212,7 +214,6 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_COOKED_FISH: case E_ITEM_COOKED_PORKCHOP: case E_ITEM_COOKIE: - case E_ITEM_GOLDEN_APPLE: case E_ITEM_GOLDEN_CARROT: case E_ITEM_MELON_SLICE: case E_ITEM_MUSHROOM_SOUP: @@ -618,29 +619,39 @@ bool cItemHandler::GetPlacementBlockTypeMeta( +bool cItemHandler::GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance) +{ + return false; +} + + + + + bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) { UNUSED(a_Item); - - FoodInfo Info = GetFoodInfo(); + FoodInfo Info = GetFoodInfo(); if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f)) { bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation); - - // If consumed and there's chance of foodpoisoning, do it: - if (Success && (Info.PoisonChance > 0)) + + // Give effects + cEntityEffect::eType EffectType; + int EffectDurationTicks; + short EffectIntensity; + float Chance; + if (Success && GetEatEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance)) { cFastRandom r1; - if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0) + if (r1.NextFloat() < Chance) { - a_Player->FoodPoison(600); // Give the player food poisoning for 30 seconds. + a_Player->AddEntityEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance); } } - return Success; } - return false; } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 1d5f59f3e..8b554ee34 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -3,6 +3,7 @@ #include "../Defines.h" #include "../Item.h" +#include "../Entities/EntityEffect.h" @@ -71,23 +72,24 @@ public: struct FoodInfo { - double Saturation; int FoodLevel; - int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning + double Saturation; FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) : - Saturation(a_Saturation), FoodLevel(a_FoodLevel), - PoisonChance(a_PoisonChance) + Saturation(a_Saturation) { } } ; - /** Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) */ + /** Returns the FoodInfo for this item. (FoodRecovery and Saturation) */ virtual FoodInfo GetFoodInfo(); - + + /** If this function returns true, it sets the arguments to a effect who will be activated when you eat the item. */ + virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance); + /** Lets the player eat a selected item. Returns true if the player ate the item */ - virtual bool EatItem(cPlayer *a_Player, cItem *a_Item); + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item); /** Indicates if this item is a tool */ virtual bool IsTool(void); From 87d195171a7069139cbbc9dfc2534ddd6c1ad867 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 23:08:08 +0200 Subject: [PATCH 061/751] Changed IsSolid to FullyOccupiesVoxel --- src/Blocks/BlockIce.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index c085e9290..c38630fe3 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -32,7 +32,7 @@ public: } BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); - if (!cBlockInfo::IsSolid(BlockBelow) && !IsBlockLava(BlockBelow) && !IsBlockWater(BlockBelow)) + if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) { return; } From cfaef0de386640fcc1729e6574fd481949bb6a3c Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 23:11:51 +0200 Subject: [PATCH 062/751] Capitalised "incremental" --- src/World.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index b247a79bc..7500b163d 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3176,17 +3176,17 @@ void cWorld::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicke cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile) { - AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "incremental"); + AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "Incremental"); if (SimulatorName.empty()) { - LOGWARNING("[Physics] RedstoneSimulator not present or empty in %s, using the default of \"incremental\".", GetIniFileName().c_str()); - SimulatorName = "incremental"; + LOGWARNING("[Physics] RedstoneSimulator not present or empty in %s, using the default of \"Incremental\".", GetIniFileName().c_str()); + SimulatorName = "Incremental"; } cRedstoneSimulator * res = NULL; - if (NoCaseCompare(SimulatorName, "incremental") == 0) + if (NoCaseCompare(SimulatorName, "Incremental") == 0) { res = new cIncrementalRedstoneSimulator(*this); } From 09b63565bcdd5977988d390f33de47b17cc7b7b7 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 23:19:05 +0200 Subject: [PATCH 063/751] Use "default:" in switch. --- src/BlockEntities/BeaconEntity.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 55c5ccb7f..805e5e61f 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -73,10 +73,13 @@ bool cBeaconEntity::IsValidEffect(cEntityEffect::eType a_Effect, char a_BeaconLe case cEntityEffect::effSpeed: return (a_BeaconLevel >= 1); case cEntityEffect::effHaste: return (a_BeaconLevel >= 1); case cEntityEffect::effNoEffect: return true; - } - LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, (int)a_Effect); - return false; + default: + { + LOGD("%s: Invalid beacon effect: %d", __FUNCTION__, (int)a_Effect); + return false; + } + } } From 160fa3a9a9466da646bc7631543e813690f5a77d Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 31 Jul 2014 23:56:49 +0200 Subject: [PATCH 064/751] Import Statistics.h --- src/ClientHandle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index bd76ef227..79ec8c9b6 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -3,6 +3,7 @@ #include "ClientHandle.h" #include "Server.h" #include "World.h" +#include "Statistics.h" #include "Entities/Pickup.h" #include "Bindings/PluginManager.h" #include "Entities/Player.h" From 86d84bcb7391b6a862b53436623b97140529aa83 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 1 Aug 2014 17:29:17 +0200 Subject: [PATCH 065/751] Compile fix. --- src/ClientHandle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 79ec8c9b6..2d665a06c 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -3,7 +3,6 @@ #include "ClientHandle.h" #include "Server.h" #include "World.h" -#include "Statistics.h" #include "Entities/Pickup.h" #include "Bindings/PluginManager.h" #include "Entities/Player.h" @@ -635,7 +634,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, if (!m_Player->IsSwimming()) { - m_Player->GetStatManager().AddValue(eStatistic::statJumps, 1); + m_Player->GetStatManager().AddValue(statJumps, 1); m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2); } } From bfe11024ac9bf202baa49a88d9370738ab0fcb8b Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 1 Aug 2014 19:37:08 +0200 Subject: [PATCH 066/751] Added missing HOOK_BLOCK_SPREAD call. --- src/Simulator/FireSimulator.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 69dc7164e..cdb5abde2 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -359,18 +359,26 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel continue; } + int AbsX = (Neighbour->GetPosX() * cChunkDef::Width) + X; + int Y = a_RelY + gNeighborCoords[i].y; + int AbsZ = (Neighbour->GetPosZ() * cChunkDef::Width) + Z; + if (BlockType == E_BLOCK_TNT) { - int AbsX = X + Neighbour->GetPosX() * cChunkDef::Width; - int AbsZ = Z + Neighbour->GetPosZ() * cChunkDef::Width; - - m_World.SpawnPrimedTNT(AbsX, a_RelY + gNeighborCoords[i].y, AbsZ, 0); - Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, E_BLOCK_AIR, 0); + m_World.SpawnPrimedTNT(AbsX, Y, AbsZ, 0); + Neighbour->SetBlock(X, a_RelY + Y, Z, E_BLOCK_AIR, 0); return; } bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance); - Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0); + if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, AbsX, Y, AbsZ, ssFireSpread)) + { + Neighbour->SetBlock(X, Y, Z, E_BLOCK_FIRE, 0); + } + else + { + Neighbour->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); + } } // for i - Coords[] } From c865fc8ca501e7405da2ce8353628373e4526053 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 1 Aug 2014 22:05:40 +0100 Subject: [PATCH 067/751] Improved endermen code a little --- MCServer/monsters.ini | 2 +- src/Mobs/Enderman.cpp | 68 +++++++++++++++++++++++++++++++------------ src/Mobs/Enderman.h | 4 +++ src/Mobs/Monster.cpp | 4 ++- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini index b631fc1a9..d29b01d8f 100644 --- a/MCServer/monsters.ini +++ b/MCServer/monsters.ini @@ -44,7 +44,7 @@ MaxHealth=10 AttackRange=2.0 AttackRate=1 AttackDamage=4.0 -SightDistance=25.0 +SightDistance=64.0 MaxHealth=40 [ZombiePigman] diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index a32e4e175..1dc73d654 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -14,9 +14,10 @@ class cPlayerLookCheck : public cPlayerListCallback { public: - cPlayerLookCheck(Vector3d a_EndermanPos) : + cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) : m_Player(NULL), - m_EndermanPos(a_EndermanPos) + m_EndermanPos(a_EndermanPos), + m_SightDistance(a_SightDistance) { } @@ -30,8 +31,8 @@ public: Vector3d Direction = m_EndermanPos - a_Player->GetPosition(); - // Don't check players who are more then 64 blocks away - if (Direction.SqrLength() > 64) + // Don't check players who are more then SightDistance (64) blocks away + if (Direction.Length() > m_SightDistance) { return false; } @@ -48,7 +49,7 @@ public: // 0.09 rad ~ 5 degrees // If the player's crosshair is within 5 degrees of the enderman, it counts as looking - if (dot > cos(0.09)) + if (dot <= cos(0.09)) { return false; } @@ -69,6 +70,7 @@ public: protected: cPlayer * m_Player; Vector3d m_EndermanPos; + int m_SightDistance; } ; @@ -107,7 +109,7 @@ void cEnderman::CheckEventSeePlayer() return; } - cPlayerLookCheck Callback(GetPosition()); + cPlayerLookCheck Callback(GetPosition(), m_SightDistance); if (m_World->ForEachPlayer(Callback)) { return; @@ -115,20 +117,10 @@ void cEnderman::CheckEventSeePlayer() ASSERT(Callback.GetPlayer() != NULL); - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); - - // Check if the chunk the enderman is in is lit - if (!m_World->IsChunkLighted(ChunkX, ChunkZ)) + if (!CheckLight()) { - m_World->QueueLightChunk(ChunkX, ChunkZ); - return; - } - - // Enderman only attack if the skylight is higher than 7 - if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) <= 7) - { - // TODO: Teleport the enderman to a random spot + // Insufficient light for enderman to become aggravated + // TODO: Teleport to a suitable location return; } @@ -140,6 +132,19 @@ void cEnderman::CheckEventSeePlayer() GetWorld()->BroadcastEntityMetadata(*this); } } + + + + + +void cEnderman::CheckEventLostPlayer(void) +{ + super::CheckEventLostPlayer(); + if (!CheckLight()) + { + EventLosePlayer(); + } +} @@ -151,3 +156,28 @@ void cEnderman::EventLosePlayer() m_bIsScreaming = false; GetWorld()->BroadcastEntityMetadata(*this); } + + + + + +bool cEnderman::CheckLight() +{ + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); + + // Check if the chunk the enderman is in is lit + if (!m_World->IsChunkLighted(ChunkX, ChunkZ)) + { + m_World->QueueLightChunk(ChunkX, ChunkZ); + return true; + } + + // Enderman only attack if the skylight is lower or equal to 8 + if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() > 8) + { + return false; + } + + return true; +} diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h index da857ee09..4583746e7 100644 --- a/src/Mobs/Enderman.h +++ b/src/Mobs/Enderman.h @@ -19,12 +19,16 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void CheckEventSeePlayer(void) override; + virtual void CheckEventLostPlayer(void) override; virtual void EventLosePlayer(void) override; bool IsScreaming(void) const {return m_bIsScreaming; } BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; } NIBBLETYPE GetCarriedMeta(void) const {return CarriedMeta; } + /** Returns if the current sky light level is sufficient for the enderman to become aggravated */ + bool CheckLight(void); + private: bool m_bIsScreaming; diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 622a67816..94df991a3 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -276,7 +276,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) if (DoesPosYRequireJump((int)floor(m_Destination.y))) { m_bOnGround = false; - AddSpeedY(5.2); // Jump!! + + // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport + AddPosY(1.2); // Jump!! } } From b5c0a4aa3ac904a7db1ee23e92a73dad6e1d4ade Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 1 Aug 2014 22:15:14 +0100 Subject: [PATCH 068/751] Fixed issues with autocomplete and time loading * Fixes #1274 --- src/World.cpp | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index 865ddfcc6..d2213d1e5 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -578,8 +578,7 @@ void cWorld::Start(void) m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); - m_TimeOfDay = IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay); - + if (GetDimension() == dimOverworld) { m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether"); @@ -597,6 +596,7 @@ void cWorld::Start(void) InitialiseGeneratorDefaults(IniFile); InitialiseAndLoadMobSpawningValues(IniFile); + SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", m_TimeOfDay)); m_ChunkMap = new cChunkMap(this); @@ -3153,21 +3153,47 @@ int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProje void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results) { + typedef std::pair pair_t; + size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space + AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word + + if (LastWord.empty()) + { + return; + } + + std::vector UsernamesByWeight; + cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr) { - size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space - - AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word AString PlayerName ((*itr)->GetName()); - size_t Found = PlayerName.find(LastWord); // Try to find last word in playername + AString::size_type Found = PlayerName.find(LastWord); // Try to find last word in playername if (Found == AString::npos) { continue; // No match } - a_Results.push_back(PlayerName); // Match! + UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight + } + Lock.Unlock(); + + std::sort(UsernamesByWeight.begin(), UsernamesByWeight.end()); // Sort lexicographically (by the first value, then second), so higher weights (usernames with match closer to start) come first (#1274) + + /* TODO: Uncomment once migrated to C++11 + std::transform( + UsernamesByWeight.begin(), + UsernamesByWeight.end(), + std::back_inserter(a_Results), + [](const pair_t & p) { return p.first; } + ); + */ + + a_Results.reserve(UsernamesByWeight.size()); + for (std::vector::const_iterator itr = UsernamesByWeight.begin(); itr != UsernamesByWeight.end(); ++itr) + { + a_Results.push_back(itr->second); } } From 3b4255dbfe6dc0fa2ecd861221a2ed5b124a81ad Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 2 Aug 2014 00:14:05 +0200 Subject: [PATCH 069/751] Fixed a bug who can used from hacked clients. --- src/BlockEntities/BeaconEntity.cpp | 2 ++ src/ClientHandle.cpp | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 805e5e61f..dcf659f47 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -90,6 +90,7 @@ bool cBeaconEntity::SetPrimaryEffect(cEntityEffect::eType a_Effect) { if (!IsValidEffect(a_Effect, m_BeaconLevel)) { + m_PrimaryEffect = cEntityEffect::effNoEffect; return false; } @@ -111,6 +112,7 @@ bool cBeaconEntity::SetSecondaryEffect(cEntityEffect::eType a_Effect) { if (!IsValidEffect(a_Effect, m_BeaconLevel)) { + m_SecondaryEffect = cEntityEffect::effNoEffect; return false; } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index d71c6a9d8..72257028a 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -795,7 +795,22 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length) Window->SetSlot(*m_Player, 0, cItem()); BeaconWindow->GetBeaconEntity()->SetPrimaryEffect(PrimaryEffect); - BeaconWindow->GetBeaconEntity()->SetSecondaryEffect(SecondaryEffect); + + // Valid effect check. Vanilla don't check this, but we do it :) + if ( + (SecondaryEffect == cEntityEffect::effNoEffect) || + (SecondaryEffect == cEntityEffect::effRegeneration) || + (SecondaryEffect == BeaconWindow->GetBeaconEntity()->GetPrimaryEffect()) + ) + { + BeaconWindow->GetBeaconEntity()->SetSecondaryEffect(SecondaryEffect); + } + else + { + BeaconWindow->GetBeaconEntity()->SetSecondaryEffect(cEntityEffect::effNoEffect); + } + + m_Player->CloseWindow(true); } From a44fbf2338e98e81bbc55780c92fa8780b061f9f Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sat, 2 Aug 2014 21:44:16 +0200 Subject: [PATCH 070/751] Added proper trees and height for SwamplandM biome --- src/Generating/HeiGen.cpp | 2 +- src/Generating/Trees.cpp | 2 +- src/Generating/Trees.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 870ceef7f..ba11b31b4 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -432,7 +432,7 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] = /* biExtremeHillsM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 131 /* biFlowerForest */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 132 /* biTaigaM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 133 - /* biSwamplandM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 134 + /* biSwamplandM */ { 1.0f, 2.0f, 1.10f, 5.0f, 0.01f, 8.0f, 60}, // 134 // Biomes 135 .. 139 unused, 5 empty placeholders here: {}, {}, {}, {}, {}, // 135 .. 139 diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 32594d0b4..1b0f2dc14 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -181,6 +181,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No return; } + case biSwamplandM: case biSwampland: { // Swamp trees: @@ -233,7 +234,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biExtremeHillsM: case biFlowerForest: case biTaigaM: - case biSwamplandM: case biIcePlainsSpikes: case biJungleM: case biJungleEdgeM: diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 1f6ac4dff..c9eb7de80 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -28,6 +28,7 @@ logs can overwrite others(leaves), but others shouldn't overwrite logs. This is #define CASE_TREE_ALLOWED_BLOCKS \ case E_BLOCK_AIR: \ case E_BLOCK_LEAVES: \ + case E_BLOCK_NEW_LEAVES: \ case E_BLOCK_SNOW: \ case E_BLOCK_TALL_GRASS: \ case E_BLOCK_DEAD_BUSH: \ @@ -40,6 +41,7 @@ logs can overwrite others(leaves), but others shouldn't overwrite logs. This is /* case E_BLOCK_LEAVES: LEAVES are a special case, they can be overwritten only by log. Handled in cChunkMap::ReplaceTreeBlocks(). */ \ case E_BLOCK_SNOW: \ case E_BLOCK_TALL_GRASS: \ + case E_BLOCK_BIG_FLOWER: \ case E_BLOCK_DEAD_BUSH: \ case E_BLOCK_SAPLING: \ case E_BLOCK_VINES From 7915c4ca7cf4a7afaa86e62757d23364ead4c69e Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 2 Aug 2014 21:44:02 -0700 Subject: [PATCH 071/751] Entity.cpp: On portal check, use if-else for current dimension If current dimension corresponds with the portal (nether portal in the nether) send to the overworld, else send to the portal dimension. No need to switch on the dimension and exclude potential others. --- src/Entities/Entity.cpp | 122 +++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 64 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index da578013d..c2727e6a1 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1068,42 +1068,38 @@ bool cEntity::DetectPortal() } m_PortalCooldownData.m_TicksDelayed = 0; - switch (GetWorld()->GetDimension()) + if (GetWorld()->GetDimension() == dimNether) { - case dimNether: + if (GetWorld()->GetLinkedOverworldName().empty()) { - if (GetWorld()->GetLinkedOverworldName().empty()) - { - return false; - } - - m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn - - if (IsPlayer()) - { - ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); // Send a respawn packet before world is loaded/generated so the client isn't left in limbo - } - - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + return false; } - case dimOverworld: + + m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn + + if (IsPlayer()) { - if (GetWorld()->GetNetherWorldName().empty()) - { - return false; - } - - m_PortalCooldownData.m_ShouldPreventTeleportation = true; - - if (IsPlayer()) - { - ((cPlayer *)this)->AwardAchievement(achEnterPortal); - ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); - } - - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimOverworld); // Send a respawn packet before world is loaded/generated so the client isn't left in limbo } - default: return false; + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + } + else + { + if (GetWorld()->GetNetherWorldName().empty()) + { + return false; + } + + m_PortalCooldownData.m_ShouldPreventTeleportation = true; + + if (IsPlayer()) + { + ((cPlayer *)this)->AwardAchievement(achEnterPortal); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether); + } + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false); } } case E_BLOCK_END_PORTAL: @@ -1113,45 +1109,43 @@ bool cEntity::DetectPortal() return false; } - switch (GetWorld()->GetDimension()) + if (GetWorld()->GetDimension() == dimEnd) { - case dimEnd: + + if (GetWorld()->GetLinkedOverworldName().empty()) { - if (GetWorld()->GetLinkedOverworldName().empty()) - { - return false; - } - - m_PortalCooldownData.m_ShouldPreventTeleportation = true; - - if (IsPlayer()) - { - cPlayer * Player = (cPlayer *)this; - Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); - Player->GetClientHandle()->SendRespawn(dimOverworld); - } - - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); + return false; } - case dimOverworld: + + m_PortalCooldownData.m_ShouldPreventTeleportation = true; + + if (IsPlayer()) { - if (GetWorld()->GetEndWorldName().empty()) - { - return false; - } - - m_PortalCooldownData.m_ShouldPreventTeleportation = true; - - if (IsPlayer()) - { - ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); - ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); - } - - return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + cPlayer * Player = (cPlayer *)this; + Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); + Player->GetClientHandle()->SendRespawn(dimOverworld); } - default: return false; + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedOverworldName()), false); } + else + { + if (GetWorld()->GetEndWorldName().empty()) + { + return false; + } + + m_PortalCooldownData.m_ShouldPreventTeleportation = true; + + if (IsPlayer()) + { + ((cPlayer *)this)->AwardAchievement(achEnterTheEnd); + ((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd); + } + + return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false); + } + } default: break; } From 3ffec92e7930c0b4bb14073f23a9d12313bd6cbc Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 2 Aug 2014 22:27:27 -0700 Subject: [PATCH 072/751] Removed unused cPlayer::FoodPoison function --- src/Entities/Player.cpp | 9 --------- src/Entities/Player.h | 3 --- 2 files changed, 12 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index ca3b1f367..d3d5a61d4 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -580,15 +580,6 @@ void cPlayer::AddFoodExhaustion(double a_Exhaustion) -void cPlayer::FoodPoison(int a_NumTicks) -{ - AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1); -} - - - - - void cPlayer::StartEating(void) { // Set the timer: diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 917e87a89..e3203d6d1 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -286,9 +286,6 @@ public: /** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */ void AddFoodExhaustion(double a_Exhaustion); - /** Starts the food poisoning for the specified amount of ticks */ - void FoodPoison(int a_NumTicks); - /** Returns true if the player is currently in the process of eating the currently equipped item */ bool IsEating(void) const { return (m_EatingFinishTick >= 0); } From 9ecce2366e81ae66c77312220e378ff2f1b02a24 Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 2 Aug 2014 22:35:29 -0700 Subject: [PATCH 073/751] Code reduction and clarity fixes --- src/Entities/Entity.cpp | 28 +++++++++------------------- src/Entities/Player.cpp | 17 +++++++---------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index c2727e6a1..042e3b868 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -543,10 +543,7 @@ void cEntity::KilledBy(TakeDamageInfo & a_TDI) void cEntity::Heal(int a_HitPoints) { m_Health += a_HitPoints; - if (m_Health > m_MaxHealth) - { - m_Health = m_MaxHealth; - } + m_Health = std::min(m_Health, m_MaxHealth); } @@ -555,7 +552,7 @@ void cEntity::Heal(int a_HitPoints) void cEntity::SetHealth(int a_Health) { - m_Health = std::max(0, std::min(m_MaxHealth, a_Health)); + m_Health = Clamp(a_Health, 0, m_MaxHealth); } @@ -1264,10 +1261,10 @@ void cEntity::HandleAir(void) SetSpeedY(1); // Float in the water } - // Either reduce air level or damage player - if (m_AirLevel < 1) + if (m_AirLevel <= 0) { - if (m_AirTickTimer < 1) + // Either reduce air level or damage player + if (m_AirTickTimer <= 0) { // Damage player TakeDamage(dtDrowning, NULL, 1, 1, 0); @@ -1552,17 +1549,10 @@ void cEntity::SetHeight(double a_Height) void cEntity::SetMass(double a_Mass) { - if (a_Mass > 0) - { - m_Mass = a_Mass; - } - else - { - // Make sure that mass is not zero. 1g is the default because we - // have to choose a number. It's perfectly legal to have a mass - // less than 1g as long as is NOT equal or less than zero. - m_Mass = 0.001; - } + // Make sure that mass is not zero. 1g is the default because we + // have to choose a number. It's perfectly legal to have a mass + // less than 1g as long as is NOT equal or less than zero. + m_Mass = std::max(a_Mass, 0.001); } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index d3d5a61d4..d1d7349a6 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -527,7 +527,7 @@ void cPlayer::SetFoodLevel(int a_FoodLevel) void cPlayer::SetFoodSaturationLevel(double a_FoodSaturationLevel) { - m_FoodSaturationLevel = std::max(0.0, std::min(a_FoodSaturationLevel, (double)m_FoodLevel)); + m_FoodSaturationLevel = Clamp(a_FoodSaturationLevel, 0.0, (double) m_FoodLevel); } @@ -545,7 +545,7 @@ void cPlayer::SetFoodTickTimer(int a_FoodTickTimer) void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel) { - m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 40.0)); + m_FoodExhaustionLevel = Clamp(a_FoodExhaustionLevel, 0.0, 40.0); } @@ -700,16 +700,13 @@ double cPlayer::GetMaxSpeed(void) const { return m_FlyingMaxSpeed; } + else if (m_IsSprinting) + { + return m_SprintingMaxSpeed; + } else { - if (m_IsSprinting) - { - return m_SprintingMaxSpeed; - } - else - { - return m_NormalMaxSpeed; - } + return m_NormalMaxSpeed; } } From e461df00302939cd767ae0c6a31ce22fc94e977c Mon Sep 17 00:00:00 2001 From: archshift Date: Sun, 3 Aug 2014 02:20:48 -0700 Subject: [PATCH 074/751] Entity.cpp: Air timer comment fix --- src/Entities/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 042e3b868..a274e6780 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1263,7 +1263,7 @@ void cEntity::HandleAir(void) if (m_AirLevel <= 0) { - // Either reduce air level or damage player + // Runs the air tick timer to check whether the player should be damaged if (m_AirTickTimer <= 0) { // Damage player From dd9a19e3952ce48fe8d3ad4825889f17c69ac55a Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 3 Aug 2014 15:31:59 +0200 Subject: [PATCH 075/751] VillageGen: Fixed a typo in comment --- src/Generating/VillageGen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index cade923c9..a7f66b75e 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -168,7 +168,7 @@ protected: /** The density for this village. Used to refrain from populating all house connectors. Range [0, 100] */ int m_Density; - /** Borders of the vilalge - no item may reach out of this cuboid. */ + /** Borders of the village - no item may reach out of this cuboid. */ cCuboid m_Borders; /** Prefabs to use for buildings */ From 6ce61d1a6fd912c99284875a9052475e06fba432 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 11:57:05 +0200 Subject: [PATCH 076/751] Fixed a ToLua warning - operator = not supported. --- src/BlockID.cpp | 2 +- src/Cuboid.cpp | 2 +- src/Cuboid.h | 6 +++++- src/Entities/EntityEffect.cpp | 2 +- src/Entities/EntityEffect.h | 2 +- src/Globals.h | 4 ++-- src/Matrix4.h | 4 ++++ src/WorldStorage/WorldStorage.h | 2 +- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/BlockID.cpp b/src/BlockID.cpp index d145a2e5b..07a1fc9e5 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -17,7 +17,7 @@ class cBlockIDMap // Making the map case-insensitive: struct Comparator { - bool operator()(const AString & a_Item1, const AString & a_Item2) const + bool operator ()(const AString & a_Item1, const AString & a_Item2) const { return (NoCaseCompare(a_Item1, a_Item2) > 0); } diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index 26e86c77b..8891cfcb1 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -24,7 +24,7 @@ static bool DoIntervalsIntersect(int a_Min1, int a_Max1, int a_Min2, int a_Max2) //////////////////////////////////////////////////////////////////////////////// // cCuboid: -cCuboid & cCuboid::operator=(cCuboid a_Other) +cCuboid & cCuboid::operator =(cCuboid a_Other) { std::swap(p1, a_Other.p1); std::swap(p2, a_Other.p2); diff --git a/src/Cuboid.h b/src/Cuboid.h index d62cf8063..c205156ec 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -20,7 +20,11 @@ public: cCuboid(int a_X1, int a_Y1, int a_Z1) : p1(a_X1, a_Y1, a_Z1), p2(a_X1, a_Y1, a_Z1) {} cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) {} - cCuboid & operator=(cCuboid a_Other); + // tolua_end + + cCuboid & operator =(cCuboid a_Other); + + // tolua_begin void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2); void Assign(const cCuboid & a_SrcCuboid); diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index 39314f256..3e28392f4 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -170,7 +170,7 @@ cEntityEffect::cEntityEffect(const cEntityEffect & a_OtherEffect): -cEntityEffect & cEntityEffect::operator=(cEntityEffect a_OtherEffect) +cEntityEffect & cEntityEffect::operator =(cEntityEffect a_OtherEffect) { std::swap(m_Ticks, a_OtherEffect.m_Ticks); std::swap(m_Duration, a_OtherEffect.m_Duration); diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h index f9c1e4eb2..47c298f57 100644 --- a/src/Entities/EntityEffect.h +++ b/src/Entities/EntityEffect.h @@ -71,7 +71,7 @@ public: /** Creates an entity effect by copying another @param a_OtherEffect The other effect to copy */ - cEntityEffect & operator=(cEntityEffect a_OtherEffect); + cEntityEffect & operator =(cEntityEffect a_OtherEffect); virtual ~cEntityEffect(void) {} diff --git a/src/Globals.h b/src/Globals.h index b35af9604..60ee456c9 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -156,11 +156,11 @@ template class SizeChecker; template class SizeChecker; template class SizeChecker; -// A macro to disallow the copy constructor and operator= functions +// A macro to disallow the copy constructor and operator = functions // This should be used in the private: declarations for any class that shouldn't allow copying itself #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName &); \ - void operator=(const TypeName &) + void operator =(const TypeName &) // A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc #define UNUSED(X) (void)(X) diff --git a/src/Matrix4.h b/src/Matrix4.h index 081847b9f..61ea60bfd 100644 --- a/src/Matrix4.h +++ b/src/Matrix4.h @@ -34,6 +34,8 @@ public: { *this = a_Rhs; } + + // tolua_end inline Matrix4 & operator = (const Matrix4 & a_Rhs) { @@ -43,6 +45,8 @@ public: } return *this; } + + // tolua_begin inline T & operator [] (int a_N) { diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index 978a5b5d1..5d8aa4589 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -93,7 +93,7 @@ protected: sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} - bool operator==(const sChunkLoad other) const + bool operator ==(const sChunkLoad other) const { return this->m_ChunkX == other.m_ChunkX && this->m_ChunkY == other.m_ChunkY && From 836de13797577289e91478ce89de65d39096f9e4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 11:57:26 +0200 Subject: [PATCH 077/751] Added cPlayer::GetUUID(). --- src/Entities/Player.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index e3203d6d1..e26808bfc 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -417,6 +417,9 @@ public: /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } + + /** 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 From 36d19723362a4b1756c03fdc2cda7b6cace4b97b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 12:08:00 +0200 Subject: [PATCH 078/751] ToLua driver: disabled output buffering. --- lib/tolua++/src/bin/lua/_driver.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/tolua++/src/bin/lua/_driver.lua b/lib/tolua++/src/bin/lua/_driver.lua index 87ecd42ea..1ca18862b 100644 --- a/lib/tolua++/src/bin/lua/_driver.lua +++ b/lib/tolua++/src/bin/lua/_driver.lua @@ -3,6 +3,9 @@ local mobdebugfound, mobdebug = pcall(require, "mobdebug") if mobdebugfound then mobdebug.start() end +-- Disable buffering for stdout, so that the results appear immediately: +io.output():setvbuf("no") + -- The list of valid arguments that the ToLua scripts can process: local KnownArgs = { ['v'] = true, From 003f18bd0f7593bddf5c6af89e3f6fc13632300d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 12:12:28 +0200 Subject: [PATCH 079/751] Added cMojangAPI:GetUUIDFromPlayerName(). This is a simpler way to ask for a single name -> uuid conversion. --- MCServer/Plugins/APIDump/APIDesc.lua | 1 + src/Protocol/MojangAPI.cpp | 28 ++++++++++++++++++++++++++++ src/Protocol/MojangAPI.h | 7 +++++++ 3 files changed, 36 insertions(+) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 1fa2608b3..4f8567530 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1630,6 +1630,7 @@ a_Player:OpenWindow(Window); Functions = { AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp." }, + GetUUIDFromPlayerName = { Params = "PlayerName, [UseOnlyCached]", Return = "UUID", Notes = "Returns the UUID that corresponds to the given playername, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the playername is not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, GetUUIDsFromPlayerNames = { Params = "PlayerNames, [UseOnlyCached]", Return = "table", Notes = "Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. If UseOnlyCached is false (the default), queries the Mojang servers for the results that are not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 45baa5a4f..f53df1cba 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -129,6 +129,34 @@ void cMojangAPI::Start(cIniFile & a_SettingsIni) +AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached) +{ + // Convert the playername to lowercase: + AString lcPlayerName(a_PlayerName); + StrToLower(lcPlayerName); + + // Request the cache to populate any names not yet contained: + if (!a_UseOnlyCached) + { + AStringVector PlayerNames; + PlayerNames.push_back(lcPlayerName); + CacheNamesToUUIDs(PlayerNames); + } + + // Retrieve from cache: + cNameToUUIDMap::const_iterator itr = m_NameToUUID.find(lcPlayerName); + if (itr == m_NameToUUID.end()) + { + // No UUID found + return ""; + } + return itr->second.m_PlayerName; +} + + + + + AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached) { // Convert all playernames to lowercase: diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index ac8995bb5..7f3ef4e39 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -45,6 +45,13 @@ public: Note: only checks the string's length, not the actual content. */ static AString MakeUUIDDashed(const AString & a_UUID); + /** 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. + If a_UseOnlyCached is false and the name is not found in the cache, it is looked up online, which is a blocking + operation, do not use this in world-tick thread! */ + AString GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached = false); + // tolua_end /** Converts the player names into UUIDs. From 98a13d97b3c913a7601b6c69c302f10b61851501 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 21:31:04 +0200 Subject: [PATCH 080/751] Trailing whitespace fix. --- src/Mobs/Enderman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 1dc73d654..0a1b6491a 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -103,7 +103,7 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cEnderman::CheckEventSeePlayer() -{ +{ if (m_Target != NULL) { return; From 21f52676f3848d58ff1e4eb511c691d4a4ed824b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 21:32:20 +0200 Subject: [PATCH 081/751] cMojangAPI: Added UUID-to-Name lookup. Also fixed the bindings, now all functions are static-like. --- MCServer/Plugins/APIDump/APIDesc.lua | 17 +- src/Bindings/ManualBindings.cpp | 98 ++++++- src/Protocol/Authenticator.cpp | 4 +- src/Protocol/MojangAPI.cpp | 385 ++++++++++++++++++++++++--- src/Protocol/MojangAPI.h | 97 +++++-- src/Root.h | 2 +- 6 files changed, 531 insertions(+), 72 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 4f8567530..ad3b24ca5 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1613,8 +1613,7 @@ a_Player:OpenWindow(Window); some of these calls will wait for a response from the network, and so shouldn't be used while the server is fully running (or at least when there are players connected) to avoid percepted lag.

- Some functions are static and do not require an instance to be called. For others, you need to get - the singleton instance of this class using {{cRoot}}'s GetMojangAPI() function.

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

Mojang uses two formats for UUIDs, short and dashed. MCServer works with short UUIDs internally, but will convert to dashed UUIDs where needed - in the protocol login for example. The MakeUUIDShort() @@ -1629,11 +1628,12 @@ a_Player:OpenWindow(Window); ]], Functions = { - AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp." }, - GetUUIDFromPlayerName = { Params = "PlayerName, [UseOnlyCached]", Return = "UUID", Notes = "Returns the UUID that corresponds to the given playername, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the playername is not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, - GetUUIDsFromPlayerNames = { Params = "PlayerNames, [UseOnlyCached]", Return = "table", Notes = "Returns a table that contains the map, 'PlayerName' -> 'UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. If UseOnlyCached is false (the default), queries the Mojang servers for the results that are not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, - MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, - MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed and short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, + AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "(STATIC) Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp. Accepts both short or dashed UUIDs. " }, + GetPlayerNameFromUUID = { Params = "UUID, [UseOnlyCached]", Return = "PlayerName", Notes = "(STATIC) Returns the playername that corresponds to the given UUID, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the UUID is not in the cache. The UUID can be either short or dashed.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, + GetUUIDFromPlayerName = { Params = "PlayerName, [UseOnlyCached]", Return = "UUID", Notes = "(STATIC) Returns the (short) UUID that corresponds to the given playername, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the playername is not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, + GetUUIDsFromPlayerNames = { Params = "PlayerNames, [UseOnlyCached]", Return = "table", Notes = "(STATIC) Returns a table that contains the map, 'PlayerName' -> '(short) UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. If UseOnlyCached is false (the default), queries the Mojang servers for the results that are not in the cache.
WARNING: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." }, + MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, + MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." }, }, }, @@ -2017,7 +2017,6 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ]], Functions = { - Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." }, BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server. No formatting is done by the server." }, BroadcastChatFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." }, BroadcastChatFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." }, @@ -2028,12 +2027,12 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for all players with names partially (or fully) matching the name string provided." }, ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature:

function Callback({{cPlayer|cPlayer}})
" }, ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature:
function Callback({{cWorld|cWorld}})
" }, + Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." }, GetCraftingRecipes = { Params = "", Return = "{{cCraftingRecipe|cCraftingRecipe}}", Notes = "Returns the CraftingRecipes object" }, GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." }, GetFurnaceFuelBurnTime = { Params = "{{cItem|Fuel}}", Return = "number", Notes = "(STATIC) Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel." }, 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." }, - GetMojangAPI = { Params = "", Return = "{{cMojangAPI}}", Notes = "Returns the {{cMojangAPI}} 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." }, diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 34f0d7e30..042ffb19e 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2158,6 +2158,99 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L) +static int tolua_cMojangAPI_AddPlayerNameToUUIDMapping(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cMojangAPI") || + !S.CheckParamString(2) || + !S.CheckParamString(3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Retrieve the parameters: + AString UUID, PlayerName; + S.GetStackValue(2, PlayerName); + S.GetStackValue(3, UUID); + + // Store in the cache: + cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(PlayerName, UUID); + return 0; +} + + + + + +static int tolua_cMojangAPI_GetPlayerNameFromUUID(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cMojangAPI") || + !S.CheckParamString(2) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + AString UUID; + S.GetStackValue(2, UUID); + + // If the UseOnlyCached param was given, read it; default to false + bool ShouldUseCacheOnly = false; + if (lua_gettop(L) == 3) + { + ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0); + lua_pop(L, 1); + } + + // Return the PlayerName: + AString PlayerName = cRoot::Get()->GetMojangAPI().GetPlayerNameFromUUID(UUID, ShouldUseCacheOnly); + S.Push(PlayerName); + return 1; +} + + + + + +static int tolua_cMojangAPI_GetUUIDFromPlayerName(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cMojangAPI") || + !S.CheckParamString(2) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + AString PlayerName; + S.GetStackValue(2, PlayerName); + + // If the UseOnlyCached param was given, read it; default to false + bool ShouldUseCacheOnly = false; + if (lua_gettop(L) == 3) + { + ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0); + lua_pop(L, 1); + } + + // Return the UUID: + AString UUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(PlayerName, ShouldUseCacheOnly); + S.Push(UUID); + return 1; +} + + + + + static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L) { cLuaState S(L); @@ -3158,7 +3251,10 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cMojangAPI"); - tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cMojangAPI_GetUUIDsFromPlayerNames); + tolua_function(tolua_S, "AddPlayerNameToUUIDMapping", tolua_cMojangAPI_AddPlayerNameToUUIDMapping); + 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_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 160564d51..984000795 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -191,8 +191,8 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S a_UUID = cMojangAPI::MakeUUIDShort(root.get("id", "").asString()); a_Properties = root["properties"]; - // Store the player's UUID in the NameToUUID map in MojangAPI: - cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(a_UserName, a_UUID); + // Store the player's profile in the MojangAPI caches: + cRoot::Get()->GetMojangAPI().AddPlayerProfile(a_UserName, a_UUID, a_Properties); return true; } diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index f53df1cba..9fdf07380 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -25,8 +25,10 @@ const int MAX_PER_QUERY = 100; -#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com" -#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft" +#define DEFAULT_NAME_TO_UUID_SERVER "api.mojang.com" +#define DEFAULT_NAME_TO_UUID_ADDRESS "/profiles/minecraft" +#define DEFAULT_UUID_TO_PROFILE_SERVER "sessionserver.mojang.com" +#define DEFAULT_UUID_TO_PROFILE_ADDRESS "/session/minecraft/profile/%UUID%?unsigned=false" @@ -96,12 +98,66 @@ static const AString & StarfieldCACert(void) +//////////////////////////////////////////////////////////////////////////////// +// cMojangAPI::sProfile: + +cMojangAPI::sProfile::sProfile( + const AString & a_PlayerName, + const AString & a_UUID, + const Json::Value & a_Properties, + Int64 a_DateTime +) : + m_PlayerName(a_PlayerName), + m_UUID(a_UUID), + m_Textures(), + m_TexturesSignature(), + m_DateTime(a_DateTime) +{ + /* + Example a_Profile contents: + "properties": + [ + { + "name": "textures", + "value": "eyJ0aW1lc3RhbXAiOjE0MDcwNzAzMjEyNzEsInByb2ZpbGVJZCI6ImIxY2FmMjQyMDJhODQxYTc4MDU1YTA3OWM0NjBlZWU3IiwicHJvZmlsZU5hbWUiOiJ4b2Z0IiwiaXNQdWJsaWMiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iNzc5YmFiZjVhNTg3Zjk0OGFkNjc0N2VhOTEyNzU0MjliNjg4Mjk1YWUzYzA3YmQwZTJmNWJmNGQwNTIifX19", + "signature": "XCty+jGEF39hEPrPhYNnCX087kPaoCjYruzYI/DS4nkL5hbjnkSM5Rh15hnUyv/FHhC8OF5rif3D1tQjtMI19KSVaXoUFXpbJM8/+PB8GDgEbX8Fc3u9nYkzOcM/xfxdYsFAdFhLQMkvase/BZLSuPhdy9DdI+TCrO7xuSTZfYmmwVuWo3w5gCY+mSIAnqltnOzaOOTcly75xvO0WYpVk7nJdnR2tvSi0wfrQPDrIg/uzhX7p0SnDqijmBU4QaNez/TNKiFxy69dAzt0RSotlQzqkDbyVKhhv9a4eY8h3pXi4UMftKEj4FAKczxLImkukJXuOn5NN15/Q+le0rJVBC60/xjKIVzltEsMN6qjWD0lQjey7WEL+4pGhCVuWY5KzuZjFvgqszuJTFz7lo+bcHiceldJtea8/fa02eTRObZvdLxbWC9ZfFY0IhpOVKfcLdno/ddDMNMQMi5kMrJ8MZZ/PcW1w5n7MMGWPGCla1kOaC55AL0QYSMGRVEZqgU9wXI5M7sHGZKGM4mWxkbEJYBkpI/p3GyxWgV6v33ZWlsz65TqlNrR1gCLaoFCm7Sif8NqPBZUAONHYon0roXhin/DyEanS93WV6i6FC1Wisscjq2AcvnOlgTo/5nN/1QsMbjNumuMGo37sqjRqlXoPb8zEUbAhhztYuJjEfQ2Rd8=" + } + ] + */ + + // Parse the Textures and TexturesSignature from the Profile: + if (!a_Properties.isArray()) + { + // Properties is not a valid array, bail out + return; + } + Json::UInt Size = a_Properties.size(); + for (Json::UInt i = 0; i < Size; i++) + { + const Json::Value & Prop = a_Properties[i]; + AString PropName = Prop.get("name", "").asString(); + if (PropName != "textures") + { + continue; + } + m_Textures = Prop.get("value", "").asString(); + m_TexturesSignature = Prop.get("signature", "").asString(); + break; + } // for i - Properties[] +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cMojangAPI: cMojangAPI::cMojangAPI(void) : m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER), - m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS) + m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), + m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER), + m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS) { } @@ -120,8 +176,10 @@ cMojangAPI::~cMojangAPI() void cMojangAPI::Start(cIniFile & a_SettingsIni) { - m_NameToUUIDServer = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); - m_NameToUUIDAddress = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); + m_NameToUUIDServer = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDServer", DEFAULT_NAME_TO_UUID_SERVER); + m_NameToUUIDAddress = a_SettingsIni.GetValueSet("MojangAPI", "NameToUUIDAddress", DEFAULT_NAME_TO_UUID_ADDRESS); + m_UUIDToProfileServer = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER); + m_UUIDToProfileAddress = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS); LoadCachesFromDisk(); } @@ -135,7 +193,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U AString lcPlayerName(a_PlayerName); StrToLower(lcPlayerName); - // Request the cache to populate any names not yet contained: + // Request the cache to query the name if not yet cached: if (!a_UseOnlyCached) { AStringVector PlayerNames; @@ -144,7 +202,8 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U } // Retrieve from cache: - cNameToUUIDMap::const_iterator itr = m_NameToUUID.find(lcPlayerName); + cCSLock Lock(m_CSNameToUUID); + cProfileMap::const_iterator itr = m_NameToUUID.find(lcPlayerName); if (itr == m_NameToUUID.end()) { // No UUID found @@ -157,6 +216,44 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U +AString cMojangAPI::GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnlyCached) +{ + // Normalize the UUID to lowercase short format that is used as the map key: + AString UUID = StrToLower(MakeUUIDShort(a_UUID)); + + // Retrieve from caches: + { + cCSLock Lock(m_CSUUIDToProfile); + cProfileMap::const_iterator itr = m_UUIDToProfile.find(UUID); + if (itr != m_UUIDToProfile.end()) + { + return itr->second.m_PlayerName; + } + } + { + cCSLock Lock(m_CSUUIDToName); + cProfileMap::const_iterator itr = m_UUIDToName.find(UUID); + if (itr != m_UUIDToName.end()) + { + return itr->second.m_PlayerName; + } + } + + // Name not yet cached, request cache and retry: + if (!a_UseOnlyCached) + { + CacheUUIDToProfile(UUID); + return GetPlayerNameFromUUID(a_UUID, true); + } + + // No value found, none queried. Return an error: + return ""; +} + + + + + AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached) { // Convert all playernames to lowercase: @@ -180,7 +277,7 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = PlayerNames.begin(), end = PlayerNames.end(); itr != end; ++itr, ++idx) { - cNameToUUIDMap::const_iterator itrN = m_NameToUUID.find(*itr); + cProfileMap::const_iterator itrN = m_NameToUUID.find(*itr); if (itrN != m_NameToUUID.end()) { res[idx] = itrN->second.m_UUID; @@ -196,10 +293,39 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) { AString lcName(a_PlayerName); - AString UUID = MakeUUIDShort(a_UUID); + AString UUID = StrToLower(MakeUUIDShort(a_UUID)); Int64 Now = time(NULL); - cCSLock Lock(m_CSNameToUUID); - m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(a_PlayerName, UUID, Now); + { + cCSLock Lock(m_CSNameToUUID); + m_NameToUUID[StrToLower(lcName)] = sProfile(a_PlayerName, UUID, "", "", Now); + } + { + cCSLock Lock(m_CSUUIDToName); + m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now); + } +} + + + + + +void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties) +{ + AString lcName(a_PlayerName); + AString UUID = StrToLower(MakeUUIDShort(a_UUID)); + Int64 Now = time(NULL); + { + cCSLock Lock(m_CSNameToUUID); + m_NameToUUID[StrToLower(lcName)] = sProfile(a_PlayerName, UUID, "", "", Now); + } + { + cCSLock Lock(m_CSUUIDToName); + m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now); + } + { + cCSLock Lock(m_CSUUIDToProfile); + m_UUIDToProfile[UUID] = sProfile(a_PlayerName, UUID, a_Properties, Now); + } } @@ -337,6 +463,7 @@ void cMojangAPI::LoadCachesFromDisk(void) // Open up the SQLite DB: SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); + db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); // Clean up old entries: { @@ -345,16 +472,40 @@ void cMojangAPI::LoadCachesFromDisk(void) stmt.bind(1, LimitDateTime); stmt.exec(); } - - // Retrieve all remaining entries:: - SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); - while (stmt.executeStep()) { - AString PlayerName = stmt.getColumn(0); - AString UUID = stmt.getColumn(1); - Int64 DateTime = stmt.getColumn(2); - AString lcPlayerName = PlayerName; - m_NameToUUID[StrToLower(lcPlayerName)] = sUUIDRecord(PlayerName, UUID, DateTime); + SQLite::Statement stmt(db, "DELETE FROM UUIDToProfile WHERE DateTime < ?"); + Int64 LimitDateTime = time(NULL) - MAX_AGE; + stmt.bind(1, LimitDateTime); + stmt.exec(); + } + + // Retrieve all remaining entries: + { + SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); + while (stmt.executeStep()) + { + AString PlayerName = stmt.getColumn(0); + AString UUID = stmt.getColumn(1); + Int64 DateTime = stmt.getColumn(2); + AString lcPlayerName = PlayerName; + UUID = StrToLower(MakeUUIDShort(UUID)); + m_NameToUUID[StrToLower(lcPlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime); + m_UUIDToName[UUID] = sProfile(PlayerName, UUID, "", "", DateTime); + } + } + { + SQLite::Statement stmt(db, "SELECT PlayerName, UUID, Textures, TexturesSignature, DateTime FROM UUIDToProfile"); + while (stmt.executeStep()) + { + AString PlayerName = stmt.getColumn(0); + AString UUID = stmt.getColumn(1); + AString Textures = stmt.getColumn(2); + AString TexturesSignature = stmt.getColumn(2); + Int64 DateTime = stmt.getColumn(4); + AString lcPlayerName = PlayerName; + UUID = StrToLower(MakeUUIDShort(UUID)); + m_UUIDToProfile[StrToLower(lcPlayerName)] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime); + } } } catch (const SQLite::Exception & ex) @@ -374,26 +525,51 @@ void cMojangAPI::SaveCachesToDisk(void) // Open up the SQLite DB: SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); + db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); // Remove all entries: db.exec("DELETE FROM PlayerNameToUUID"); + db.exec("DELETE FROM UUIDToProfile"); - // Save all cache entries: - SQLite::Statement stmt(db, "INSERT INTO PlayerNameToUUID(PlayerName, UUID, DateTime) VALUES (?, ?, ?)"); + // Save all cache entries - m_PlayerNameToUUID: Int64 LimitDateTime = time(NULL) - MAX_AGE; - cCSLock Lock(m_CSNameToUUID); - for (cNameToUUIDMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr) { - if (itr->second.m_DateTime < LimitDateTime) + SQLite::Statement stmt(db, "INSERT INTO PlayerNameToUUID(PlayerName, UUID, DateTime) VALUES (?, ?, ?)"); + cCSLock Lock(m_CSNameToUUID); + for (cProfileMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr) { - // This item is too old, do not save - continue; + if (itr->second.m_DateTime < LimitDateTime) + { + // This item is too old, do not save + continue; + } + stmt.bind(1, itr->second.m_PlayerName); + stmt.bind(2, itr->second.m_UUID); + stmt.bind(3, itr->second.m_DateTime); + stmt.exec(); + stmt.reset(); + } + } + + // Save all cache entries - m_UUIDToProfile: + { + SQLite::Statement stmt(db, "INSERT INTO UUIDToProfile(UUID, PlayerName, Textures, TexturesSignature, DateTime) VALUES (?, ?, ?, ?, ?)"); + cCSLock Lock(m_CSUUIDToProfile); + for (cProfileMap::const_iterator itr = m_UUIDToProfile.begin(), end = m_UUIDToProfile.end(); itr != end; ++itr) + { + if (itr->second.m_DateTime < LimitDateTime) + { + // This item is too old, do not save + continue; + } + stmt.bind(1, itr->second.m_UUID); + stmt.bind(2, itr->second.m_PlayerName); + stmt.bind(3, itr->second.m_Textures); + stmt.bind(4, itr->second.m_TexturesSignature); + stmt.bind(5, itr->second.m_DateTime); + stmt.exec(); + stmt.reset(); } - stmt.bind(1, itr->second.m_PlayerName); - stmt.bind(2, itr->second.m_UUID); - stmt.bind(3, itr->second.m_DateTime); - stmt.exec(); - stmt.reset(); } } catch (const SQLite::Exception & ex) @@ -487,22 +663,145 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); - cCSLock Lock(m_CSNameToUUID); - for (size_t idx = 0; idx < JsonCount; ++idx) { - Json::Value & Val = root[idx]; - AString JsonName = Val.get("name", "").asString(); - AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); - if (JsonUUID.empty()) + cCSLock Lock(m_CSNameToUUID); + for (size_t idx = 0; idx < JsonCount; ++idx) { - continue; - } - AString lcName = JsonName; - m_NameToUUID[StrToLower(lcName)] = sUUIDRecord(JsonName, JsonUUID, Now); - } // for idx - root[] + Json::Value & Val = root[idx]; + AString JsonName = Val.get("name", "").asString(); + AString JsonUUID = StrToLower(MakeUUIDShort(Val.get("id", "").asString())); + if (JsonUUID.empty()) + { + continue; + } + AString lcName = JsonName; + m_NameToUUID[StrToLower(lcName)] = sProfile(JsonName, JsonUUID, "", "", Now); + } // for idx - root[] + } // cCSLock (m_CSNameToUUID) + + // Also cache the UUIDToName: + { + cCSLock Lock(m_CSUUIDToName); + for (size_t idx = 0; idx < JsonCount; ++idx) + { + Json::Value & Val = root[idx]; + AString JsonName = Val.get("name", "").asString(); + AString JsonUUID = StrToLower(MakeUUIDShort(Val.get("id", "").asString())); + if (JsonUUID.empty()) + { + continue; + } + m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); + } // for idx - root[] + } } // while (!NamesToQuery.empty()) } + +void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) +{ + ASSERT(a_UUID.size() == 32); + + // Check if already present: + { + if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) + { + return; + } + } + + // Create the request address: + AString Address = m_UUIDToProfileAddress; + ReplaceString(Address, "%UUID%", a_UUID); + + // Create the HTTP request: + AString Request; + Request += "GET " + Address + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding + Request += "Host: " + m_UUIDToProfileServer + "\r\n"; + Request += "User-Agent: MCServer\r\n"; + Request += "Connection: close\r\n"; + Request += "Content-Length: 0\r\n"; + Request += "\r\n"; + + // Get the response from the server: + AString Response; + if (!SecureRequest(m_UUIDToProfileServer, Request, Response)) + { + return; + } + + // Check the HTTP status line: + const AString Prefix("HTTP/1.1 200 OK"); + AString HexDump; + if (Response.compare(0, Prefix.size(), Prefix)) + { + LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return; + } + + // Erase the HTTP headers from the response: + size_t idxHeadersEnd = Response.find("\r\n\r\n"); + if (idxHeadersEnd == AString::npos) + { + LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); + LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return; + } + Response.erase(0, idxHeadersEnd + 4); + + // Parse the returned string into Json: + Json::Reader reader; + Json::Value root; + if (!reader.parse(Response, root, false) || !root.isObject()) + { + LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); + LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return; + } + + /* Example response: + { + "id": "b1caf24202a841a78055a079c460eee7", + "name": "xoft", + "properties": + [ + { + "name": "textures", + "value": "eyJ0aW1lc3RhbXAiOjE0MDcwNzAzMjEyNzEsInByb2ZpbGVJZCI6ImIxY2FmMjQyMDJhODQxYTc4MDU1YTA3OWM0NjBlZWU3IiwicHJvZmlsZU5hbWUiOiJ4b2Z0IiwiaXNQdWJsaWMiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iNzc5YmFiZjVhNTg3Zjk0OGFkNjc0N2VhOTEyNzU0MjliNjg4Mjk1YWUzYzA3YmQwZTJmNWJmNGQwNTIifX19", + "signature": "XCty+jGEF39hEPrPhYNnCX087kPaoCjYruzYI/DS4nkL5hbjnkSM5Rh15hnUyv/FHhC8OF5rif3D1tQjtMI19KSVaXoUFXpbJM8/+PB8GDgEbX8Fc3u9nYkzOcM/xfxdYsFAdFhLQMkvase/BZLSuPhdy9DdI+TCrO7xuSTZfYmmwVuWo3w5gCY+mSIAnqltnOzaOOTcly75xvO0WYpVk7nJdnR2tvSi0wfrQPDrIg/uzhX7p0SnDqijmBU4QaNez/TNKiFxy69dAzt0RSotlQzqkDbyVKhhv9a4eY8h3pXi4UMftKEj4FAKczxLImkukJXuOn5NN15/Q+le0rJVBC60/xjKIVzltEsMN6qjWD0lQjey7WEL+4pGhCVuWY5KzuZjFvgqszuJTFz7lo+bcHiceldJtea8/fa02eTRObZvdLxbWC9ZfFY0IhpOVKfcLdno/ddDMNMQMi5kMrJ8MZZ/PcW1w5n7MMGWPGCla1kOaC55AL0QYSMGRVEZqgU9wXI5M7sHGZKGM4mWxkbEJYBkpI/p3GyxWgV6v33ZWlsz65TqlNrR1gCLaoFCm7Sif8NqPBZUAONHYon0roXhin/DyEanS93WV6i6FC1Wisscjq2AcvnOlgTo/5nN/1QsMbjNumuMGo37sqjRqlXoPb8zEUbAhhztYuJjEfQ2Rd8=" + } + ] + } + */ + + // Store the returned result into caches: + AString PlayerName = root.get("name", "").asString(); + if (PlayerName.empty()) + { + // No valid playername, bail out + return; + } + Json::Value Properties = root.get("properties", ""); + Int64 Now = time(NULL); + { + cCSLock Lock(m_CSUUIDToProfile); + m_UUIDToProfile[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); + } + { + cCSLock Lock(m_CSUUIDToName); + m_UUIDToName[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); + } + { + AString lcPlayerName(PlayerName); + cCSLock Lock(m_CSNameToUUID); + m_NameToUUID[StrToLower(lcPlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); + } +} + + + + diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 7f3ef4e39..08e799c73 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -11,6 +11,11 @@ #include +namespace Json +{ + class Value; +} + @@ -45,14 +50,24 @@ 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. If a_UseOnlyCached is false and the name is not found in the cache, it is looked up online, which is a blocking - operation, do not use this in world-tick thread! */ + operation, do not use this in world-tick thread! + If you have multiple names to resolve, use the GetUUIDsFromPlayerNames() function, it uses a single request for multiple names. */ AString GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached = false); - // tolua_end + /** Converts a UUID into a playername. + The returned playername will be empty on error. + Both short and dashed UUID formats are accepted. + Uses both m_UUIDToName and m_UUIDToProfile to search for the value. Uses m_UUIDToProfile for cache. + If a_UseOnlyCached is true, the function only consults the cached values. + If a_UseOnlyCached is false and the name is not found in the cache, it is looked up online, which is a blocking + operation, do not use this in world-tick thread! */ + AString GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnlyCached = false); /** Converts the player names into UUIDs. a_PlayerName[idx] will be converted to UUID and returned as idx-th value @@ -62,36 +77,61 @@ public: operation, do not use this in world-tick thread! */ AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName, bool a_UseOnlyCached = false); - // tolua_begin - /** Called by the Authenticator to add a PlayerName -> UUID mapping that it has received from authenticating a user. This adds the cache item and "refreshes" it if existing, adjusting its datetime stamp to now. */ void AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID); - // tolua_end - + /** 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); + protected: - struct sUUIDRecord + /** Holds data for a single player profile. */ + struct sProfile { - AString m_PlayerName; // Case-correct playername - AString m_UUID; - Int64 m_DateTime; // UNIXtime of the UUID lookup + AString m_PlayerName; // Case-correct playername + AString m_UUID; // Short lowercased UUID + AString m_Textures; // The Textures field of the profile properties + AString m_TexturesSignature; // The signature of the Textures field of the profile properties + Int64 m_DateTime; // UNIXtime of the profile lookup - sUUIDRecord(void) : + /** Default constructor for the container's sake. */ + sProfile(void) : + m_PlayerName(), m_UUID(), + m_Textures(), + m_TexturesSignature(), m_DateTime(time(NULL)) { } - sUUIDRecord(const AString & a_PlayerName, const AString & a_UUID, Int64 a_DateTime) : + /** Constructor for the storage creation. */ + sProfile( + const AString & a_PlayerName, + const AString & a_UUID, + const AString & a_Textures, + const AString & a_TexturesSignature, + Int64 a_DateTime + ) : m_PlayerName(a_PlayerName), m_UUID(a_UUID), + m_Textures(a_Textures), + m_TexturesSignature(a_TexturesSignature), m_DateTime(a_DateTime) { } + + /** Constructor that parses the values from the Json profile. */ + sProfile( + const AString & a_PlayerName, + const AString & a_UUID, + const Json::Value & a_Properties, + Int64 a_DateTime + ); }; - typedef std::map cNameToUUIDMap; // maps Lowercased PlayerName to sUUIDRecord + typedef std::map cProfileMap; + /** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */ AString m_NameToUUIDServer; @@ -100,12 +140,32 @@ protected: For example "/profiles/page/1". */ AString m_NameToUUIDAddress; - /** Cache for the Name-to-UUID lookups. The map key is expected lowercased. Protected by m_CSNameToUUID. */ - cNameToUUIDMap m_NameToUUID; + /** The server to connect to when converting UUID to profile. For example "sessionserver.mojang.com". */ + AString m_UUIDToProfileServer; + + /** The URL to use for converting UUID to profile, without the server part. + Will replace %UUID% with the actual UUID. For example "session/minecraft/profile/%UUID%?unsigned=false". */ + AString m_UUIDToProfileAddress; + + /** Cache for the Name-to-UUID lookups. The map key is lowercased PlayerName. Protected by m_CSNameToUUID. */ + cProfileMap m_NameToUUID; /** Protects m_NameToUUID against simultaneous multi-threaded access. */ cCriticalSection m_CSNameToUUID; + /** Cache for the Name-to-UUID lookups. The map key is lowercased short UUID. Protected by m_CSUUIDToName. */ + cProfileMap m_UUIDToName; + + /** Protects m_UUIDToName against simultaneous multi-threaded access. */ + cCriticalSection m_CSUUIDToName; + + /** Cache for the UUID-to-profile lookups. The map key is lowercased short UUID. + Protected by m_CSUUIDToProfile. */ + cProfileMap m_UUIDToProfile; + + /** Protects m_UUIDToProfile against simultaneous multi-threaded access. */ + cCriticalSection m_CSUUIDToProfile; + /** Loads the caches from a disk storage. */ void LoadCachesFromDisk(void); @@ -113,10 +173,15 @@ protected: /** Saves the caches to a disk storage. */ void SaveCachesToDisk(void); - /** Makes sure all specified names are in the cache. Downloads any missing ones from Mojang API servers. + /** Makes sure all specified names are in the m_PlayerNameToUUID cache. Downloads any missing ones from Mojang API servers. Names that are not valid are not added into the cache. ASSUMEs that a_PlayerNames contains lowercased player names. */ void CacheNamesToUUIDs(const AStringVector & a_PlayerNames); + + /** Makes sure the specified UUID is in the m_UUIDToProfile cache. If missing, downloads it from Mojang API servers. + 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); } ; // tolua_export diff --git a/src/Root.h b/src/Root.h index 5cb82edda..1cd175ab4 100644 --- a/src/Root.h +++ b/src/Root.h @@ -88,7 +88,7 @@ public: cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } - cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } // tolua_export + cMojangAPI & GetMojangAPI (void) { return m_MojangAPI; } /** Queues a console command for execution through the cServer class. The command will be executed in the tick thread From f5aaf52210369862a045c074429428012607c445 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 21:32:53 +0200 Subject: [PATCH 082/751] Debuggers: Added a Name-from-UUID cMojangAPI test. --- MCServer/Plugins/Debuggers/Debuggers.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 075cfa40c..7e220952e 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -339,6 +339,13 @@ function TestUUIDFromName() end LOG("UUID-from-Name resolution tests finished.") + + LOG("Performing a Name-from-UUID test...") + -- local NameToTest = "aloe_vera" + local NameToTest = "xoft" + local Name = cMojangAPI:GetPlayerNameFromUUID(UUIDs[NameToTest]) + LOG("Name(" .. UUIDs[NameToTest] .. ") = '" .. Name .. "', expected '" .. NameToTest .. "'.") + LOG("Name-from-UUID test finished.") end From 3136fc6246a6e0c3ab19eb3dddb1badc7c427ee3 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 22:03:48 +0200 Subject: [PATCH 083/751] Wolf uses UUID for owner. Fixes #1277. --- src/Mobs/Wolf.cpp | 6 ++- src/Mobs/Wolf.h | 10 +++- src/WorldStorage/NBTChunkSerializer.cpp | 10 ++-- src/WorldStorage/WSSAnvil.cpp | 69 +++++++++++++++++++++---- src/WorldStorage/WSSAnvil.h | 4 ++ 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 5bb97d30e..4fe1ff1d6 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -68,6 +68,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player) { if (!IsTame() && !IsAngry()) { + // If the player is holding a bone, try to tame the wolf: if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE) { if (!a_Player.IsGameModeCreative()) @@ -77,14 +78,16 @@ void cWolf::OnRightClicked(cPlayer & a_Player) if (m_World->GetTickRandomNumber(7) == 0) { + // Taming succeeded SetMaxHealth(20); SetIsTame(true); - SetOwner(a_Player.GetName()); + SetOwner(a_Player.GetName(), a_Player.GetUUID()); m_World->BroadcastEntityStatus(*this, esWolfTamed); m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); } else { + // Taming failed m_World->BroadcastEntityStatus(*this, esWolfTaming); m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); } @@ -92,6 +95,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player) } else if (IsTame()) { + // Feed the wolf, restoring its health, or dye its collar: switch (a_Player.GetEquippedItem().m_ItemType) { case E_ITEM_RAW_BEEF: diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 2e83db701..7500854f8 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -29,7 +29,8 @@ public: bool IsTame (void) const { return m_IsTame; } bool IsBegging (void) const { return m_IsBegging; } bool IsAngry (void) const { return m_IsAngry; } - AString GetOwner (void) const { return m_OwnerName; } + AString GetOwnerName (void) const { return m_OwnerName; } + AString GetOwnerUUID (void) const { return m_OwnerUUID; } int GetCollarColor(void) const { return m_CollarColor; } // Set functions @@ -37,8 +38,12 @@ public: void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; } void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; } void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; } - void SetOwner (const AString & a_NewOwner) { m_OwnerName = a_NewOwner; } void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; } + void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID) + { + m_OwnerName = a_NewOwnerName; + m_OwnerUUID = a_NewOwnerUUID; + } protected: @@ -47,6 +52,7 @@ protected: bool m_IsBegging; bool m_IsAngry; AString m_OwnerName; + AString m_OwnerUUID; int m_CollarColor; } ; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 601cd8833..ecda9b8fd 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -569,10 +569,12 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) } case cMonster::mtWolf: { - m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner()); - m_Writer.AddByte("Sitting", (((const cWolf *)a_Monster)->IsSitting() ? 1 : 0)); - m_Writer.AddByte("Angry", (((const cWolf *)a_Monster)->IsAngry() ? 1 : 0)); - m_Writer.AddInt("CollarColor", ((const cWolf *)a_Monster)->GetCollarColor()); + const cWolf & Wolf = *((cWolf *)a_Monster); + m_Writer.AddString("Owner", Wolf.GetOwnerName()); + m_Writer.AddString("OwnerUUID", Wolf.GetOwnerUUID()); + m_Writer.AddByte("Sitting", Wolf.IsSitting() ? 1 : 0); + m_Writer.AddByte("Angry", Wolf.IsAngry() ? 1 : 0); + m_Writer.AddInt("CollarColor", Wolf.GetCollarColor()); break; } case cMonster::mtZombie: diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index d3a156ee1..434f1e21f 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -15,6 +15,7 @@ #include "../ItemGrid.h" #include "../StringCompression.h" #include "../SetChunkData.h" +#include "../Root.h" #include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/ChestEntity.h" @@ -49,6 +50,8 @@ #include "../Entities/HangingEntity.h" #include "../Entities/ItemFrame.h" +#include "../Protocol/MojangAPI.h" + @@ -2411,16 +2414,9 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N { return; } - int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner"); - if (OwnerIdx > 0) - { - AString OwnerName = a_NBT.GetString(OwnerIdx); - if (OwnerName != "") - { - Monster->SetOwner(OwnerName); - Monster->SetIsTame(true); - } - } + + LoadWolfOwner(*Monster.get(), a_NBT, a_TagIdx); + int SittingIdx = a_NBT.FindChildByName(a_TagIdx, "Sitting"); if (SittingIdx > 0) { @@ -2492,6 +2488,59 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT +void cWSSAnvil::LoadWolfOwner(cWolf & a_Wolf, const cParsedNBT & a_NBT, int a_TagIdx) +{ + // Load the owner information. OwnerUUID or Owner may be specified, possibly both: + AString OwnerUUID, OwnerName; + int OwnerUUIDIdx = a_NBT.FindChildByName(a_TagIdx, "OwnerUUID"); + if (OwnerUUIDIdx > 0) + { + OwnerUUID = cMojangAPI::MakeUUIDShort(a_NBT.GetString(OwnerUUIDIdx)); + } + int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner"); + if (OwnerIdx > 0) + { + OwnerName = a_NBT.GetString(OwnerIdx); + } + if (OwnerName.empty() && OwnerUUID.empty()) + { + // There is no owner, bail out: + return; + } + + // Convert name to UUID, if needed: + if (OwnerUUID.empty()) + { + // This wolf has only playername stored (pre-1.7.6), look up the UUID + // The lookup is blocking, but we're running in a separate thread, so it's ok + OwnerUUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(OwnerName); + if (OwnerUUID.empty()) + { + // Not a known player, un-tame the wolf by bailing out + return; + } + } + + // Convert UUID to name, if needed: + if (OwnerName.empty()) + { + // The lookup is blocking, but we're running in a separate thread, so it's ok + OwnerName = cRoot::Get()->GetMojangAPI().GetPlayerNameFromUUID(OwnerUUID); + if (OwnerName.empty()) + { + // Not a known player, un-tame the wolf by bailing out + return; + } + } + + a_Wolf.SetOwner(OwnerName, OwnerUUID); + a_Wolf.SetIsTame(true); +} + + + + + bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) { double Pos[3]; diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index f8eeb8247..a41268f4c 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -21,6 +21,7 @@ class cItemGrid; class cProjectileEntity; class cHangingEntity; +class cWolf; @@ -201,6 +202,9 @@ protected: void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + /** Loads the wolf's owner information from the NBT into the specified wolf entity. */ + void LoadWolfOwner(cWolf & a_Wolf, const cParsedNBT & a_NBT, int a_TagIdx); + /// Loads entity common data from the NBT compound; returns true if successful bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); From 977a9948b9ed52d0dd8c4695ecfca981b06bb212 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 3 Aug 2014 22:15:26 +0200 Subject: [PATCH 084/751] Fixed skins in mc 1.7.9/1.7.10 --- src/Protocol/Protocol17x.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index f419c01a7..d6f4b96dc 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -3032,15 +3032,14 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); Pkt.WriteString(a_Player.GetName()); - const Json::Value & Properties = m_Client->GetProperties(); - const Json::Value::const_iterator End = Properties.end(); + const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); Pkt.WriteVarInt(Properties.size()); - for (Json::Value::iterator itr = Properties.begin(); itr != End; ++itr) + for (Json::Value::iterator itr = Properties.begin(); itr != Properties.end(); ++itr) { - Pkt.WriteString(((Json::Value)*itr).get("name", "").toStyledString()); - Pkt.WriteString(((Json::Value)*itr).get("value", "").toStyledString()); - Pkt.WriteString(((Json::Value)*itr).get("signature", "").toStyledString()); + Pkt.WriteString(((Json::Value)*itr).get("name", "").asString()); + Pkt.WriteString(((Json::Value)*itr).get("value", "").asString()); + Pkt.WriteString(((Json::Value)*itr).get("signature", "").asString()); } Pkt.WriteFPInt(a_Player.GetPosX()); From b19874e6f2c8894648c25efb0e9fa176b6688729 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 3 Aug 2014 22:19:43 +0200 Subject: [PATCH 085/751] Attempting a compilation fix for gcc / clang. --- src/StringUtils.cpp | 15 +++++++++++++++ src/StringUtils.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index b0e5a4ffe..decce8065 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -230,6 +230,21 @@ AString & StrToLower(AString & s) +AString StrToLower(const AString & s) +{ + AString res; + res.resize(s.size()); + for (AString::iterator itr = res.begin(), end = res.end(); itr != end; ++itr) + { + *itr = (char)tolower(*itr); + } + return res; +} + + + + + int NoCaseCompare(const AString & s1, const AString & s2) { #ifdef _MSC_VER diff --git a/src/StringUtils.h b/src/StringUtils.h index 30b9904d1..65363382d 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -48,6 +48,9 @@ extern AString & StrToUpper(AString & s); /// In-place string conversion to lowercase; returns the same string extern AString & StrToLower(AString & s); +/** Returns a lower-cased copy of the string */ +extern AString StrToLower(const AString & s); + /// Case-insensitive string comparison; returns 0 if the strings are the same extern int NoCaseCompare(const AString & s1, const AString & s2); // tolua_export From 0911072d27820bd608bb908088419d3ec5151434 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 01:34:12 +0200 Subject: [PATCH 086/751] Attempt to fix knockback and swimming. --- src/Entities/Entity.cpp | 28 +++++++++++++--------------- src/Mobs/Monster.cpp | 12 +++++++++--- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index a274e6780..32f220897 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -244,9 +244,9 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R Vector3d Heading(0, 0, 0); if (a_Attacker != NULL) { - Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 10 : 8); + Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11); + Heading.y = 1.6; } - Heading.y = 2; TDI.Knockback = Heading * a_KnockbackAmount; DoTakeDamage(TDI); @@ -731,21 +731,19 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } NextSpeed.y += fallspeed; } - else + + // Friction + if (NextSpeed.SqrLength() > 0.0004f) { - // Friction - if (NextSpeed.SqrLength() > 0.0004f) + NextSpeed.x *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.x) < 0.05) { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) - { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; - } + NextSpeed.x = 0; + } + NextSpeed.z *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.z) < 0.05) + { + NextSpeed.z = 0; } } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 94df991a3..66c9aadeb 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -292,6 +292,10 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { Distance *= 2.5; } + else if (IsSwimming()) + { + Distance *= 1.3; + } else { // Don't let the mob move too much if he's falling. @@ -301,11 +305,13 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) AddSpeedX(Distance.x); AddSpeedZ(Distance.z); - if (m_EMState == ESCAPING) - { // Runs Faster when escaping :D otherwise they just walk away + /* It's too buggy! */ + /** if (m_EMState == ESCAPING) + { + // Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); - } + } */ } else { From 7bea90d6caca9f9b4389fe14ab49720f22cb9273 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 01:35:25 +0200 Subject: [PATCH 087/751] Fixed warnings --- src/Mobs/Monster.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 66c9aadeb..54ad869c2 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -290,16 +290,16 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) if (m_bOnGround) { - Distance *= 2.5; + Distance *= 2.5f; } else if (IsSwimming()) { - Distance *= 1.3; + Distance *= 1.3f; } else { // Don't let the mob move too much if he's falling. - Distance *= 0.25; + Distance *= 0.25f; } AddSpeedX(Distance.x); From 122344bb7a71b7b4797869083c4c61f08882927a Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 08:00:49 +0200 Subject: [PATCH 088/751] Rewritten string case manipulation to use std::transform. --- src/StringUtils.cpp | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index decce8065..0e30e8ebb 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -198,14 +198,7 @@ AString TrimString(const AString & str) AString & StrToUpper(AString & s) { - AString::iterator i = s.begin(); - AString::iterator end = s.end(); - - while (i != end) - { - *i = (char)toupper(*i); - ++i; - } + std::transform(s.begin(), s.end(), s.begin(), ::toupper); return s; } @@ -215,14 +208,7 @@ AString & StrToUpper(AString & s) AString & StrToLower(AString & s) { - AString::iterator i = s.begin(); - AString::iterator end = s.end(); - - while (i != end) - { - *i = (char)tolower(*i); - ++i; - } + std::transform(s.begin(), s.end(), s.begin(), ::tolower); return s; } @@ -232,12 +218,8 @@ AString & StrToLower(AString & s) AString StrToLower(const AString & s) { - AString res; - res.resize(s.size()); - for (AString::iterator itr = res.begin(), end = res.end(); itr != end; ++itr) - { - *itr = (char)tolower(*itr); - } + AString res(s); + std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; } From e70077361d239f3f3a9d8a94c8262d663018f901 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 11:23:35 +0200 Subject: [PATCH 089/751] Changed /** to /* --- src/Mobs/Monster.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 54ad869c2..a9889b62f 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -305,13 +305,15 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) AddSpeedX(Distance.x); AddSpeedZ(Distance.z); - /* It's too buggy! */ - /** if (m_EMState == ESCAPING) + // It's too buggy! + /* + if (m_EMState == ESCAPING) { // Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); - } */ + } + */ } else { From 8cdcfcceb38c057015d5822fa2ec06acf767f81d Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 11:26:31 +0200 Subject: [PATCH 090/751] Changed properties for-loop. --- src/Protocol/Protocol17x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index d6f4b96dc..8f3399b2f 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -3035,7 +3035,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); Pkt.WriteVarInt(Properties.size()); - for (Json::Value::iterator itr = Properties.begin(); itr != Properties.end(); ++itr) + for (Json::Value::iterator itr = Properties.begin(), end = Properties.end(); itr != end; ++itr) { Pkt.WriteString(((Json::Value)*itr).get("name", "").asString()); Pkt.WriteString(((Json::Value)*itr).get("value", "").asString()); From 054ce9bcc45018b9f024654e7d35327fbc20d119 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 11:29:40 +0200 Subject: [PATCH 091/751] Anvil: Wolf owner not saved if not present. --- src/WorldStorage/NBTChunkSerializer.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index ecda9b8fd..e435a1b1f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -570,8 +570,14 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) case cMonster::mtWolf: { const cWolf & Wolf = *((cWolf *)a_Monster); - m_Writer.AddString("Owner", Wolf.GetOwnerName()); - m_Writer.AddString("OwnerUUID", Wolf.GetOwnerUUID()); + if (!Wolf.GetOwnerName().empty()) + { + m_Writer.AddString("Owner", Wolf.GetOwnerName()); + } + if (!Wolf.GetOwnerUUID().empty()) + { + m_Writer.AddString("OwnerUUID", Wolf.GetOwnerUUID()); + } m_Writer.AddByte("Sitting", Wolf.IsSitting() ? 1 : 0); m_Writer.AddByte("Angry", Wolf.IsAngry() ? 1 : 0); m_Writer.AddInt("CollarColor", Wolf.GetCollarColor()); From 1fa210c7f91030ac18fd880fcf131e8104c0b889 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 11:16:19 +0200 Subject: [PATCH 092/751] Refactored case-conversion functions. StrToLower() returns a modified copy of the string, InPlaceLowercase() modifies the string in-place. --- src/HTTPServer/HTTPMessage.cpp | 3 +- src/Mobs/Monster.cpp | 3 +- src/Protocol/MojangAPI.cpp | 52 ++++++++++++++-------------------- src/Protocol/MojangAPI.h | 4 +-- src/StringUtils.cpp | 25 ++++++++++------ src/StringUtils.h | 7 +++-- src/WorldStorage/WSSAnvil.cpp | 7 ++++- 7 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index 4226352e9..65d73fd87 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -35,8 +35,7 @@ cHTTPMessage::cHTTPMessage(eKind a_Kind) : void cHTTPMessage::AddHeader(const AString & a_Key, const AString & a_Value) { - AString Key = a_Key; - StrToLower(Key); + AString Key = StrToLower(a_Key); cNameValueMap::iterator itr = m_Headers.find(Key); if (itr == m_Headers.end()) { diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 94df991a3..53334753a 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -710,8 +710,7 @@ AString cMonster::MobTypeToString(cMonster::eType a_MobType) cMonster::eType cMonster::StringToMobType(const AString & a_Name) { - AString lcName(a_Name); - StrToLower(lcName); + AString lcName = StrToLower(a_Name); // Binary-search for the lowercase name: int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1; diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 9fdf07380..a7aea5490 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -190,8 +190,7 @@ void cMojangAPI::Start(cIniFile & a_SettingsIni) AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached) { // Convert the playername to lowercase: - AString lcPlayerName(a_PlayerName); - StrToLower(lcPlayerName); + AString lcPlayerName = StrToLower(a_PlayerName); // Request the cache to query the name if not yet cached: if (!a_UseOnlyCached) @@ -219,7 +218,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U AString cMojangAPI::GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnlyCached) { // Normalize the UUID to lowercase short format that is used as the map key: - AString UUID = StrToLower(MakeUUIDShort(a_UUID)); + AString UUID = MakeUUIDShort(a_UUID); // Retrieve from caches: { @@ -260,8 +259,7 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player AStringVector PlayerNames; for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { - AString Lower(*itr); - PlayerNames.push_back(StrToLower(Lower)); + PlayerNames.push_back(StrToLower(*itr)); } // for itr - a_PlayerNames[] // Request the cache to populate any names not yet contained: @@ -292,12 +290,11 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) { - AString lcName(a_PlayerName); - AString UUID = StrToLower(MakeUUIDShort(a_UUID)); + AString UUID = MakeUUIDShort(a_UUID); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); - m_NameToUUID[StrToLower(lcName)] = sProfile(a_PlayerName, UUID, "", "", Now); + m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); @@ -311,12 +308,11 @@ void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties) { - AString lcName(a_PlayerName); - AString UUID = StrToLower(MakeUUIDShort(a_UUID)); + AString UUID = MakeUUIDShort(a_UUID); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); - m_NameToUUID[StrToLower(lcName)] = sProfile(a_PlayerName, UUID, "", "", Now); + m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); @@ -395,13 +391,13 @@ AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) { case 32: { - // Already is a short UUID - return a_UUID; + // Already is a short UUID, only lowercase + return StrToLower(a_UUID); } case 36: { - // Remove the dashes from the string: + // Remove the dashes from the string by appending together the parts between them: AString res; res.reserve(32); res.append(a_UUID, 0, 8); @@ -409,7 +405,7 @@ AString cMojangAPI::MakeUUIDShort(const AString & a_UUID) res.append(a_UUID, 14, 4); res.append(a_UUID, 19, 4); res.append(a_UUID, 24, 12); - return res; + return StrToLower(res); } } LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str()); @@ -427,8 +423,8 @@ AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) { case 36: { - // Already is a dashed UUID - return a_UUID; + // Already is a dashed UUID, only lowercase + return StrToLower(a_UUID); } case 32: @@ -445,7 +441,7 @@ AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID) res.append(a_UUID, 16, 4); res.push_back('-'); res.append(a_UUID, 20, 12); - return res; + return StrToLower(res); } } LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str()); @@ -487,9 +483,8 @@ void cMojangAPI::LoadCachesFromDisk(void) AString PlayerName = stmt.getColumn(0); AString UUID = stmt.getColumn(1); Int64 DateTime = stmt.getColumn(2); - AString lcPlayerName = PlayerName; - UUID = StrToLower(MakeUUIDShort(UUID)); - m_NameToUUID[StrToLower(lcPlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime); + UUID = MakeUUIDShort(UUID); + m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime); m_UUIDToName[UUID] = sProfile(PlayerName, UUID, "", "", DateTime); } } @@ -502,9 +497,8 @@ void cMojangAPI::LoadCachesFromDisk(void) AString Textures = stmt.getColumn(2); AString TexturesSignature = stmt.getColumn(2); Int64 DateTime = stmt.getColumn(4); - AString lcPlayerName = PlayerName; - UUID = StrToLower(MakeUUIDShort(UUID)); - m_UUIDToProfile[StrToLower(lcPlayerName)] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime); + UUID = MakeUUIDShort(UUID); + m_UUIDToProfile[UUID] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime); } } } @@ -669,13 +663,12 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); - AString JsonUUID = StrToLower(MakeUUIDShort(Val.get("id", "").asString())); + AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } - AString lcName = JsonName; - m_NameToUUID[StrToLower(lcName)] = sProfile(JsonName, JsonUUID, "", "", Now); + m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) @@ -686,7 +679,7 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); - AString JsonUUID = StrToLower(MakeUUIDShort(Val.get("id", "").asString())); + AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; @@ -796,9 +789,8 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) m_UUIDToName[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { - AString lcPlayerName(PlayerName); cCSLock Lock(m_CSNameToUUID); - m_NameToUUID[StrToLower(lcPlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); + m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); } } diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h index 08e799c73..6ed37625e 100644 --- a/src/Protocol/MojangAPI.h +++ b/src/Protocol/MojangAPI.h @@ -40,12 +40,12 @@ public: // tolua_begin - /** Converts the given UUID to its short form (32 bytes, no dashes). + /** 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. */ static AString MakeUUIDShort(const AString & a_UUID); - /** Converts the given UUID to its dashed form (36 bytes, 4 dashes). + /** Normalizes the given UUID to its dashed form (36 bytes, 4 dashes, lowercase). Logs a warning and returns empty string if not a UUID. Note: only checks the string's length, not the actual content. */ static AString MakeUUIDDashed(const AString & a_UUID); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 0e30e8ebb..5f88cbf64 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -196,9 +196,9 @@ AString TrimString(const AString & str) -AString & StrToUpper(AString & s) +AString & InPlaceLowercase(AString & s) { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); + std::transform(s.begin(), s.end(), s.begin(), ::tolower); return s; } @@ -206,9 +206,9 @@ AString & StrToUpper(AString & s) -AString & StrToLower(AString & s) +AString & InPlaceUppercase(AString & s) { - std::transform(s.begin(), s.end(), s.begin(), ::tolower); + std::transform(s.begin(), s.end(), s.begin(), ::toupper); return s; } @@ -227,16 +227,25 @@ AString StrToLower(const AString & s) +AString StrToUpper(const AString & s) +{ + AString res(s); + std::transform(res.begin(), res.end(), res.begin(), ::toupper); + return res; +} + + + + + int NoCaseCompare(const AString & s1, const AString & s2) { #ifdef _MSC_VER // MSVC has stricmp that compares case-insensitive: return _stricmp(s1.c_str(), s2.c_str()); #else - // Do it the hard way: - AString s1Copy(s1); - AString s2Copy(s2); - return StrToUpper(s1Copy).compare(StrToUpper(s2Copy)); + // Do it the hard way - convert both strings to lowercase: + return StrToLower(s1).compare(StrToLower(s2)); #endif // else _MSC_VER } diff --git a/src/StringUtils.h b/src/StringUtils.h index 65363382d..142aaf59b 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -43,10 +43,13 @@ extern AStringVector StringSplitAndTrim(const AString & str, const AString & del extern AString TrimString(const AString & str); // tolua_export /// In-place string conversion to uppercase; returns the same string -extern AString & StrToUpper(AString & s); +extern AString & InPlaceUppercase(AString & s); /// In-place string conversion to lowercase; returns the same string -extern AString & StrToLower(AString & s); +extern AString & InPlaceLowercase(AString & s); + +/** Returns an upper-cased copy of the string */ +extern AString StrToUpper(const AString & s); /** Returns a lower-cased copy of the string */ extern AString StrToLower(const AString & s); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 434f1e21f..a9c9ae4b5 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -2495,7 +2495,7 @@ void cWSSAnvil::LoadWolfOwner(cWolf & a_Wolf, const cParsedNBT & a_NBT, int a_Ta int OwnerUUIDIdx = a_NBT.FindChildByName(a_TagIdx, "OwnerUUID"); if (OwnerUUIDIdx > 0) { - OwnerUUID = cMojangAPI::MakeUUIDShort(a_NBT.GetString(OwnerUUIDIdx)); + OwnerUUID = a_NBT.GetString(OwnerUUIDIdx); } int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner"); if (OwnerIdx > 0) @@ -2520,6 +2520,11 @@ void cWSSAnvil::LoadWolfOwner(cWolf & a_Wolf, const cParsedNBT & a_NBT, int a_Ta return; } } + else + { + // Normalize the UUID: + OwnerUUID = cMojangAPI::MakeUUIDShort(OwnerUUID); + } // Convert UUID to name, if needed: if (OwnerName.empty()) From ff37192e945c9083d313ddc8924ef433e193f9c7 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 12:03:37 +0200 Subject: [PATCH 093/751] BasicStyleCheck: Dividers are exactly 80 slashes. --- src/CheckBasicStyle.lua | 18 +++++++++++++++++- src/Mobs/Enderman.cpp | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index 13a6d15d2..c743a84a5 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -10,11 +10,12 @@ Checks that all source files (*.cpp, *.h) use the basic style requirements of th - Spaces after comma, not before - Opening braces not at the end of a code line - Spaces after if, for, while + - Line dividers (////...) exactly 80 slashes - (TODO) Spaces before *, /, & - (TODO) Hex numbers with even digit length - (TODO) Hex numbers in lowercase - - (TODO) Line dividers (////...) exactly 80 slashes - (TODO) Not using "* "-style doxy comment continuation lines + - (TODO) Multi-level indent change Violations that cannot be checked easily: - Spaces around "+" (there are things like "a++", "++a", "a += 1", "X+", "stack +1" and ascii-drawn tables) @@ -165,6 +166,21 @@ local function ProcessFile(a_FileName) for _, pat in ipairs(g_ViolationPatterns) do ReportViolationIfFound(a_Line, a_FileName, lineCounter, pat[1], pat[2]) end + + local dividerStart, dividerEnd = a_Line:find("/////*") + if (dividerStart) then + if (dividerEnd ~= dividerStart + 79) then + ReportViolation(a_FileName, lineCounter, 1, 80, "Divider comment should have exactly 80 slashes") + end + if (dividerStart > 1) then + if ( + (a_Line:sub(1, dividerStart - 1) ~= string.rep("\t", dividerStart - 1)) or -- The divider should have only indent in front of it + (a_Line:len() > dividerEnd + 1) -- The divider should have no other text following it + ) then + ReportViolation(a_FileName, lineCounter, 1, 80, "Divider comment shouldn't have any extra text around it") + end + end + end lineCounter = lineCounter + 1 end diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 0a1b6491a..51255beb3 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -8,7 +8,7 @@ -/////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cPlayerLookCheck class cPlayerLookCheck : public cPlayerListCallback From 7bfb0b05d0514c47095ba3ec8ebb6a1073d9962a Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 13:20:16 +0200 Subject: [PATCH 094/751] CheckBasicStyle: multi-level indent change. --- src/Bindings/WebPlugin.cpp | 2 ++ src/CheckBasicStyle.lua | 17 ++++++++++++++++- src/Entities/HangingEntity.cpp | 2 +- src/Generating/Noise3DGenerator.cpp | 5 +++-- src/Generating/StructGen.cpp | 6 +++--- src/Simulator/IncrementalRedstoneSimulator.cpp | 6 +++--- src/WorldStorage/WorldStorage.h | 8 +++++--- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp index 1178c127a..4fa64d937 100644 --- a/src/Bindings/WebPlugin.cpp +++ b/src/Bindings/WebPlugin.cpp @@ -81,7 +81,9 @@ std::pair< AString, AString > cWebPlugin::GetTabNameForRequest(const HTTPRequest else // Otherwise show the first tab { if (GetTabs().size() > 0) + { Tab = *GetTabs().begin(); + } } if (Tab != NULL) diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua index c743a84a5..bf81a7cd5 100644 --- a/src/CheckBasicStyle.lua +++ b/src/CheckBasicStyle.lua @@ -11,11 +11,11 @@ Checks that all source files (*.cpp, *.h) use the basic style requirements of th - Opening braces not at the end of a code line - Spaces after if, for, while - Line dividers (////...) exactly 80 slashes + - Multi-level indent change - (TODO) Spaces before *, /, & - (TODO) Hex numbers with even digit length - (TODO) Hex numbers in lowercase - (TODO) Not using "* "-style doxy comment continuation lines - - (TODO) Multi-level indent change Violations that cannot be checked easily: - Spaces around "+" (there are things like "a++", "++a", "a += 1", "X+", "stack +1" and ascii-drawn tables) @@ -159,6 +159,7 @@ local function ProcessFile(a_FileName) -- Process each line separately: -- Ref.: http://stackoverflow.com/questions/10416869/iterate-over-possibly-empty-lines-in-a-way-that-matches-the-expectations-of-exis local lineCounter = 1 + local lastIndentLevel = 0 all:gsub("\r\n", "\n") -- normalize CRLF into LF-only string.gsub(all .. "\n", "[^\n]*\n", -- Iterate over each line, while preserving empty lines function(a_Line) @@ -167,6 +168,7 @@ local function ProcessFile(a_FileName) ReportViolationIfFound(a_Line, a_FileName, lineCounter, pat[1], pat[2]) end + -- Check that divider comments are well formed - 80 slashes plus optional indent: local dividerStart, dividerEnd = a_Line:find("/////*") if (dividerStart) then if (dividerEnd ~= dividerStart + 79) then @@ -181,6 +183,19 @@ local function ProcessFile(a_FileName) end end end + + -- Check the indent level change from the last line, if it's too much, report: + local indentStart, indentEnd = a_Line:find("\t+") + local indentLevel = 0 + if (indentStart) then + indentLevel = indentEnd - indentStart + end + if (indentLevel > 0) then + if ((lastIndentLevel - indentLevel >= 2) or (lastIndentLevel - indentLevel <= -2)) then + ReportViolation(a_FileName, lineCounter, 1, indentStart or 1, "Indent changed more than a single level between the previous line and this one: from " .. lastIndentLevel .. " to " .. indentLevel) + end + lastIndentLevel = indentLevel + end lineCounter = lineCounter + 1 end diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp index 32d2b226d..8c70c606e 100644 --- a/src/Entities/HangingEntity.cpp +++ b/src/Entities/HangingEntity.cpp @@ -24,7 +24,7 @@ cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle) { int Dir = 0; - + // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces switch (m_BlockFace) { diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index b879349ee..eb816f564 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -412,11 +412,12 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - CurFloor[x + 17 * z] = + CurFloor[x + 17 * z] = ( m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 + m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) + m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 + - AddHeight / Height[x + 17 * z]; + AddHeight / Height[x + 17 * z] + ); } } // Linear-interpolate this XZ floor: diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index 054eec345..f7e609353 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -585,10 +585,10 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc) // First update the high floor: for (int z = 0; z <= 16 / INTERPOL_Z; z++) for (int x = 0; x <= 16 / INTERPOL_X; x++) { - FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] = + FloorHi[INTERPOL_X * x + 17 * INTERPOL_Z * z] = ( m_Noise1.IntNoise3DInt(BaseX + INTERPOL_X * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) * - m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / - 256; + m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / 256 + ); } // for x, z - FloorLo[] LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi); diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index ada8de4b8..c1a2fcaae 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -847,7 +847,7 @@ void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_Rel bool m_IsPowered; public: cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - + virtual bool Item(cDropSpenserEntity * a_DropSpenser) override { a_DropSpenser->SetRedstonePower(m_IsPowered); @@ -948,7 +948,7 @@ void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_Re bool m_IsPowered; public: cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override { a_CommandBlock->SetRedstonePower(m_IsPowered); @@ -1844,7 +1844,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, i { return; } - + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index 5d8aa4589..dd07ecb64 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -95,9 +95,11 @@ protected: bool operator ==(const sChunkLoad other) const { - return this->m_ChunkX == other.m_ChunkX && - this->m_ChunkY == other.m_ChunkY && - this->m_ChunkZ == other.m_ChunkZ; + return ( + (this->m_ChunkX == other.m_ChunkX) && + (this->m_ChunkY == other.m_ChunkY) && + (this->m_ChunkZ == other.m_ChunkZ) + ); } } ; From 01e9d6311a4c27af044e8c9be3c67000124321e9 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 4 Aug 2014 14:24:46 +0100 Subject: [PATCH 095/751] Updated submodules --- MCServer/Plugins/Core | 2 +- MCServer/Plugins/ProtectionAreas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 3790f78d3..1b16c23c2 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 3790f78d3f7503ff33a423b8e73e81a275562783 +Subproject commit 1b16c23c216d359e9fe0334c63deeecc347e69bd diff --git a/MCServer/Plugins/ProtectionAreas b/MCServer/Plugins/ProtectionAreas index 9edfee930..7765048fa 160000 --- a/MCServer/Plugins/ProtectionAreas +++ b/MCServer/Plugins/ProtectionAreas @@ -1 +1 @@ -Subproject commit 9edfee93048f214175cbed7eb2a3f77f7ac4abb2 +Subproject commit 7765048fa740b8f119db72a4ccc546504f86b2ab From f5b71cc1f86c383891d2c0da7a3be5355ee1816e Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 20:16:52 +0200 Subject: [PATCH 096/751] Fixed #1286 --- src/Protocol/Protocol17x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 8f3399b2f..318342f09 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -820,7 +820,7 @@ void cProtocol172::SendPlayerAbilities(void) } Pkt.WriteByte(Flags); Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed())); - Pkt.WriteFloat((float)(0.1 * Player->GetMaxSpeed())); + Pkt.WriteFloat((float)(0.1 * Player->GetNormalMaxSpeed())); } From 434ea542e174bc686a7c981476e23d30d18989c3 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 21:48:33 +0200 Subject: [PATCH 097/751] Added arrow consuming on shooting --- src/Items/ItemBow.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index e7a77dcbc..90645dd9a 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -57,6 +57,12 @@ public: } Force = std::min(Force, 1.0); + // Has the player a arrow? + if (!a_Player->IsGameModeCreative() && !a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))) + { + return; + } + // Create the arrow entity: cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); if (Arrow == NULL) @@ -73,6 +79,10 @@ public: a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); if (!a_Player->IsGameModeCreative()) { + if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchInfinity) == 0) + { + a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW)); + } a_Player->UseEquippedItem(); } } From de9d908792c7dfbc13db87a3508a8c4b0516d01c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 4 Aug 2014 21:21:35 +0100 Subject: [PATCH 098/751] Made AllToLua output consistent --- src/Bindings/gen_LuaState_Call.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index fb1797dc0..17bae82b3 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -13,7 +13,7 @@ separate the arguments from the return values, a special type of cLuaState::cRet -print("Generating LuaState_Call.inc...") +print("Generating LuaState_Call.inc . . .") @@ -189,7 +189,7 @@ f:close() -print("LuaState_Call.inc generated") +print("LuaState_Call.inc generated.") From 0b9eb20b92f49feeb34626eef4590f7938a93480 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 4 Aug 2014 21:22:08 +0100 Subject: [PATCH 099/751] Fixed signs not staying on other signs --- src/Blocks/BlockSignPost.h | 3 ++- src/Blocks/BlockWallSign.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index ee65d099a..d0cc760b0 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -39,8 +39,9 @@ public: { return false; } + BLOCKTYPE Type = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); - return (cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))); + return ((Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); } diff --git a/src/Blocks/BlockWallSign.h b/src/Blocks/BlockWallSign.h index e837b315e..47649379e 100644 --- a/src/Blocks/BlockWallSign.h +++ b/src/Blocks/BlockWallSign.h @@ -49,8 +49,9 @@ public: int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX; int BlockZ = (a_Chunk.GetPosZ() * cChunkDef::Width) + a_RelZ; GetBlockCoordsBehindTheSign(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ), BlockX, BlockZ); + BLOCKTYPE Type = a_ChunkInterface.GetBlock(BlockX, a_RelY, BlockZ); - return (cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(BlockX, a_RelY, BlockZ))); + return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type)); } From 2e43eaaba7a29a9db5bfa11d6a1bb8b57bf02fa6 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 4 Aug 2014 22:30:13 +0200 Subject: [PATCH 100/751] Changed arrow comment. --- src/Items/ItemBow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 90645dd9a..fdc24689c 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -57,7 +57,7 @@ public: } Force = std::min(Force, 1.0); - // Has the player a arrow? + // Does the player have an arrow? if (!a_Player->IsGameModeCreative() && !a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))) { return; From 9113b45673bc9b0202ce821b8db2dbe6f4b425b9 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 4 Aug 2014 23:35:32 +0200 Subject: [PATCH 101/751] MojangAPI: Fixed PlayerNameToUUID(). --- src/Protocol/MojangAPI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index a7aea5490..823ff5469 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -208,7 +208,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U // No UUID found return ""; } - return itr->second.m_PlayerName; + return itr->second.m_UUID; } From d2d0ffee21d10aace8caa20a002daa1c887c1f39 Mon Sep 17 00:00:00 2001 From: archshift Date: Mon, 4 Aug 2014 19:43:33 -0700 Subject: [PATCH 102/751] Fixed unsigned long comparison to size_t --- src/Items/ItemHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 1c1e3b5b9..bceedaf69 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -66,7 +66,7 @@ cItemHandler * cItemHandler::m_ItemHandler[2268]; cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) { - if ((a_ItemType < 0) || ((unsigned long)a_ItemType >= ARRAYCOUNT(m_ItemHandler))) + if ((a_ItemType < 0) || ((size_t)a_ItemType >= ARRAYCOUNT(m_ItemHandler))) { // Either nothing (-1), or bad value, both cases should return the air handler if (a_ItemType < -1) From a92cff20ea59b68827a6f579d0ba9ccb40276d6b Mon Sep 17 00:00:00 2001 From: Howaner Date: Tue, 5 Aug 2014 13:47:10 +0200 Subject: [PATCH 103/751] Added Clamp() function to the lua api. --- src/Bindings/ManualBindings.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 042ffb19e..b41cd94bc 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -82,6 +82,33 @@ static int lua_do_error(lua_State* L, const char * a_pFormat, ...) // Lua bound functions with special return types +static int tolua_Clamp(lua_State * tolua_S) +{ + cLuaState LuaState(tolua_S); + int NumArgs = lua_gettop(LuaState); + if (NumArgs != 3) + { + return lua_do_error(LuaState, "Error in function call '#funcname#': Requires 3 arguments, got %i", NumArgs); + } + + if (!lua_isnumber(LuaState, 1) || !lua_isnumber(LuaState, 2) || !lua_isnumber(LuaState, 3)) + { + return lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); + } + + int Min = (int)tolua_tonumber(LuaState, 1, 0); + int Number = (int)tolua_tonumber(LuaState, 2, 0); + int Max = (int)tolua_tonumber(LuaState, 3, 0); + + int Result = std::min(std::max(Min, Number), Max); + LuaState.Push(Result); + return 1; +} + + + + + static int tolua_StringSplit(lua_State * tolua_S) { cLuaState LuaState(tolua_S); @@ -3103,6 +3130,7 @@ static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S) void ManualBindings::Bind(lua_State * tolua_S) { tolua_beginmodule(tolua_S, NULL); + tolua_function(tolua_S, "Clamp", tolua_Clamp); tolua_function(tolua_S, "StringSplit", tolua_StringSplit); tolua_function(tolua_S, "StringSplitAndTrim", tolua_StringSplitAndTrim); tolua_function(tolua_S, "LOG", tolua_LOG); From 43de9af8786243c90832b78f8c19ec92fb218392 Mon Sep 17 00:00:00 2001 From: Howaner Date: Tue, 5 Aug 2014 13:54:04 +0200 Subject: [PATCH 104/751] Added api documentation for Clamp() --- MCServer/Plugins/APIDump/APIDesc.lua | 5 +++-- src/Bindings/ManualBindings.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index ad3b24ca5..64ba80c5f 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2760,15 +2760,16 @@ end Functions = { AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFaces|face}}"}, - BlockFaceToString = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." }, + BlockFaceToString = {Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." }, BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"}, + Clamp = {Params = "Number, Min, Max", Return = "number", Notes = "Clamp the number to the specified range."}, ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"}, DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "}, EscapeString = {Params = "string", Return = "string", Notes = "Returns a copy of the string with all quotes and backslashes escaped by a backslash"}, GetChar = {Params = "String, Pos", Return = "string", Notes = "Returns one character from the string, specified by position "}, GetIniItemSet = { Params = "IniFile, SectionName, KeyName, DefaultValue", Return = "{{cItem}}", Notes = "Returns the item that has been read from the specified INI file value. If the value is not present in the INI file, the DefaultValue is stored in the file and parsed as the result. Returns empty item if the value cannot be parsed. " }, GetTime = {Return = "number", Notes = "Returns the current OS time, as a unix time stamp (number of seconds since Jan 1, 1970)"}, - IsBiomeNoDownfall = { Params = "Biome", Return = "bool", Notes = "Returns true if the biome is 'dry', that is, there is no precipitation during rains and storms." }, + IsBiomeNoDownfall = {Params = "Biome", Return = "bool", Notes = "Returns true if the biome is 'dry', that is, there is no precipitation during rains and storms." }, IsValidBlock = {Params = "BlockType", Return = "bool", Notes = "Returns true if BlockType is a known block type"}, IsValidItem = {Params = "ItemType", Return = "bool", Notes = "Returns true if ItemType is a known item type"}, ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format 'ItemTypeText:ItemDamage * Count'"}, diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index b41cd94bc..81065a7e1 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -96,8 +96,8 @@ static int tolua_Clamp(lua_State * tolua_S) return lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); } - int Min = (int)tolua_tonumber(LuaState, 1, 0); - int Number = (int)tolua_tonumber(LuaState, 2, 0); + int Number = (int)tolua_tonumber(LuaState, 1, 0); + int Min = (int)tolua_tonumber(LuaState, 2, 0); int Max = (int)tolua_tonumber(LuaState, 3, 0); int Result = std::min(std::max(Min, Number), Max); From 40e15c5ad517a6f860b39d1b225596424c3d2506 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 5 Aug 2014 18:37:00 +0200 Subject: [PATCH 105/751] 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 5f04488a97b5cdd705368937d977827ef4465d4a Mon Sep 17 00:00:00 2001 From: Howaner Date: Tue, 5 Aug 2014 18:39:18 +0200 Subject: [PATCH 106/751] Made lua clamp() compatible with all number types. --- src/Bindings/ManualBindings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 81065a7e1..9ba1501c5 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -96,11 +96,11 @@ static int tolua_Clamp(lua_State * tolua_S) return lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); } - int Number = (int)tolua_tonumber(LuaState, 1, 0); - int Min = (int)tolua_tonumber(LuaState, 2, 0); - int Max = (int)tolua_tonumber(LuaState, 3, 0); + lua_Number Number = tolua_tonumber(LuaState, 1, 0); + lua_Number Min = tolua_tonumber(LuaState, 2, 0); + lua_Number Max = tolua_tonumber(LuaState, 3, 0); - int Result = std::min(std::max(Min, Number), Max); + lua_Number Result = Clamp(Number, Min, Max); LuaState.Push(Result); return 1; } From fcfae0252503a845c98fe6e882dda69e44224094 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 5 Aug 2014 22:28:37 +0200 Subject: [PATCH 107/751] 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 108/751] 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 06942871dde1388284a4fe222040720de3923b03 Mon Sep 17 00:00:00 2001 From: Tycho Date: Tue, 5 Aug 2014 21:48:23 +0100 Subject: [PATCH 109/751] Refactored Redstone simulator not to depend on TNTEntity or DropSpenserENtity Directly --- src/BlockEntities/DropSpenserEntity.h | 7 ++-- src/BlockEntities/RedstonePoweredEntity.h | 9 +++++ src/Chunk.cpp | 34 +++++++++++++++++++ src/Chunk.h | 6 +++- .../IncrementalRedstoneSimulator.cpp | 9 +++-- 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/BlockEntities/RedstonePoweredEntity.h diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index 9f58d0b07..dabe9a27b 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -11,7 +11,7 @@ #pragma once #include "BlockEntityWithItems.h" - +#include "RedstonePoweredEntity.h" @@ -30,7 +30,8 @@ class cServer; // tolua_begin class cDropSpenserEntity : - public cBlockEntityWithItems + public cBlockEntityWithItems, + public cRedstonePoweredEntity { typedef cBlockEntityWithItems super; @@ -65,7 +66,7 @@ public: void Activate(void); /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate - void SetRedstonePower(bool a_IsPowered); + virtual void SetRedstonePower(bool a_IsPowered) override; // tolua_end diff --git a/src/BlockEntities/RedstonePoweredEntity.h b/src/BlockEntities/RedstonePoweredEntity.h new file mode 100644 index 000000000..aebba771f --- /dev/null +++ b/src/BlockEntities/RedstonePoweredEntity.h @@ -0,0 +1,9 @@ + + +// Interface class representing a blockEntity that responds to redstone +class cRedstonePoweredEntity +{ +public: +/// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate + virtual void SetRedstonePower(bool a_IsPowered) = 0; +}; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index cd7dc698c..9e06f58ec 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2127,6 +2127,40 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc +bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + switch ((*itr)->GetBlockType()) + { + case E_BLOCK_DROPPER: + case E_BLOCK_DISPENSER: + break; + default: + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; + } + + if (a_Callback.Item((cRedstonePoweredEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index 5cde3f08f..813a8b13f 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -43,6 +43,7 @@ class cBlockArea; class cFluidSimulatorData; class cMobCensus; class cMobSpawner; +class cRedstonePoweredEntity; typedef std::list cClientHandleList; typedef cItemCallback cEntityCallback; @@ -54,6 +55,7 @@ typedef cItemCallback cNoteBlockCallback; typedef cItemCallback cCommandBlockCallback; typedef cItemCallback cMobHeadCallback; typedef cItemCallback cFlowerPotCallback; +typedef cItemCallback cRedstonePoweredCallback; @@ -237,7 +239,9 @@ public: /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible - + + /** Calls the callback for the redstone powered entity at the specified coords; returns false if there's no redstone powered entity at those coords, true if found */ + bool DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback); /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index c1a2fcaae..5b2439db1 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -3,11 +3,10 @@ #include "IncrementalRedstoneSimulator.h" #include "BoundingBox.h" -#include "../BlockEntities/DropSpenserEntity.h" +#include "../BlockEntities/RedstonePoweredEntity.h" #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" -#include "../Entities/TNTEntity.h" #include "../Entities/Pickup.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" @@ -842,13 +841,13 @@ void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlock void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { class cSetPowerToDropSpenser : - public cDropSpenserCallback + public cRedstonePoweredCallback { bool m_IsPowered; public: cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - virtual bool Item(cDropSpenserEntity * a_DropSpenser) override + virtual bool Item(cRedstonePoweredEntity * a_DropSpenser) override { a_DropSpenser->SetRedstonePower(m_IsPowered); return false; @@ -857,7 +856,7 @@ void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_Rel int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithDropSpenserAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); + m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); } From 9272bd627c732771b81e6dcf6b8465404917a9d6 Mon Sep 17 00:00:00 2001 From: Tycho Date: Tue, 5 Aug 2014 22:54:36 +0100 Subject: [PATCH 110/751] Removed dependecy of redstone simulator on NoteBlock --- src/BlockEntities/NoteEntity.h | 10 +++++++++- src/BlockEntities/RedstonePoweredEntity.h | 4 ++++ src/Chunk.cpp | 1 + src/Simulator/IncrementalRedstoneSimulator.cpp | 17 ++++++----------- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index e8497da3e..f9db6cbe6 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -2,6 +2,7 @@ #pragma once #include "BlockEntity.h" +#include "RedstonePoweredEntity.h" namespace Json @@ -29,7 +30,8 @@ enum ENUM_NOTE_INSTRUMENTS // tolua_begin class cNoteEntity : - public cBlockEntity + public cBlockEntity, + public cRedstonePoweredEntity { typedef cBlockEntity super; public: @@ -38,6 +40,7 @@ public: /// Creates a new note entity. a_World may be NULL cNoteEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); + virtual ~cNoteEntity() {} bool LoadFromJson(const Json::Value & a_Value); virtual void SaveToJson(Json::Value & a_Value) override; @@ -53,6 +56,11 @@ public: virtual void UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle &) override {} + + virtual void SetRedstonePower(bool a_Value) + { + if (a_Value) MakeSound(); + } static const char * GetClassStatic(void) { return "cNoteEntity"; } diff --git a/src/BlockEntities/RedstonePoweredEntity.h b/src/BlockEntities/RedstonePoweredEntity.h index aebba771f..7d6904442 100644 --- a/src/BlockEntities/RedstonePoweredEntity.h +++ b/src/BlockEntities/RedstonePoweredEntity.h @@ -1,9 +1,13 @@ +#pragma once // Interface class representing a blockEntity that responds to redstone class cRedstonePoweredEntity { public: + + virtual ~cRedstonePoweredEntity() {}; + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate virtual void SetRedstonePower(bool a_IsPowered) = 0; }; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 9e06f58ec..1e8d0e6f0 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2141,6 +2141,7 @@ bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_Blo { case E_BLOCK_DROPPER: case E_BLOCK_DISPENSER: + case E_BLOCK_NOTE_BLOCK: break; default: // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 5b2439db1..7b3a2c2fa 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -4,7 +4,6 @@ #include "IncrementalRedstoneSimulator.h" #include "BoundingBox.h" #include "../BlockEntities/RedstonePoweredEntity.h" -#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/CommandBlockEntity.h" #include "../Entities/Pickup.h" @@ -1033,25 +1032,21 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBl if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { class cSetPowerToNoteBlock : - public cNoteBlockCallback + public cRedstonePoweredCallback { - bool m_IsPowered; public: - cSetPowerToNoteBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + cSetPowerToNoteBlock() {} - virtual bool Item(cNoteEntity * a_NoteBlock) override + virtual bool Item(cRedstonePoweredEntity * a_NoteBlock) override { - if (m_IsPowered) - { - a_NoteBlock->MakeSound(); - } + a_NoteBlock->SetRedstonePower(true); return false; } - } NoteBlockSP(m_bAreCoordsPowered); + } NoteBlockSP; int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - m_Chunk->DoWithNoteBlockAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); + m_Chunk->DoWithRedstonePoweredEntityAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } From ff7171fc5a567590dd52d4213439778f0dfcce53 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 6 Aug 2014 14:04:25 +0200 Subject: [PATCH 111/751] Resending fire to the client when the interact cancelled. --- src/ClientHandle.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 72257028a..3e046f38d 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -920,6 +920,10 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB ) { m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))->IsClickedThrough()) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); + } return; } @@ -928,6 +932,10 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB { // A plugin doesn't agree with the action, replace the block on the client and quit: m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))->IsClickedThrough()) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); + } return; } From a0ba7426c6bc2059d5db6d248ef8e582e40ce4b3 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 6 Aug 2014 13:17:05 +0100 Subject: [PATCH 112/751] Fixed multiple inhertance being output by tolua --- src/BlockEntities/DropSpenserEntity.h | 10 ++++++---- src/BlockEntities/NoteEntity.h | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/BlockEntities/DropSpenserEntity.h b/src/BlockEntities/DropSpenserEntity.h index dabe9a27b..be56447aa 100644 --- a/src/BlockEntities/DropSpenserEntity.h +++ b/src/BlockEntities/DropSpenserEntity.h @@ -30,8 +30,10 @@ class cServer; // tolua_begin class cDropSpenserEntity : - public cBlockEntityWithItems, - public cRedstonePoweredEntity + public cBlockEntityWithItems + // tolua_end + , public cRedstonePoweredEntity + // tolua_begin { typedef cBlockEntityWithItems super; @@ -65,10 +67,10 @@ public: /// Sets the dropspenser to dropspense an item in the next tick void Activate(void); + // tolua_end + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate virtual void SetRedstonePower(bool a_IsPowered) override; - - // tolua_end protected: bool m_ShouldDropSpense; ///< If true, the dropspenser will dropspense an item in the next tick diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index f9db6cbe6..dd201e0a9 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -30,8 +30,10 @@ enum ENUM_NOTE_INSTRUMENTS // tolua_begin class cNoteEntity : - public cBlockEntity, - public cRedstonePoweredEntity + public cBlockEntity + // tolua_end + , public cRedstonePoweredEntity + // tolua_begin { typedef cBlockEntity super; public: From 6acddd0cad25078ae2c67e7a0eb353e9d4d100e2 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 6 Aug 2014 13:19:22 +0100 Subject: [PATCH 113/751] Fixed style issues --- src/BlockEntities/NoteEntity.h | 5 ++++- src/BlockEntities/RedstonePoweredEntity.h | 2 +- src/Chunk.cpp | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index dd201e0a9..f538de060 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -61,7 +61,10 @@ public: virtual void SetRedstonePower(bool a_Value) { - if (a_Value) MakeSound(); + if (a_Value) + { + MakeSound(); + } } static const char * GetClassStatic(void) { return "cNoteEntity"; } diff --git a/src/BlockEntities/RedstonePoweredEntity.h b/src/BlockEntities/RedstonePoweredEntity.h index 7d6904442..f11df4fc4 100644 --- a/src/BlockEntities/RedstonePoweredEntity.h +++ b/src/BlockEntities/RedstonePoweredEntity.h @@ -8,6 +8,6 @@ public: virtual ~cRedstonePoweredEntity() {}; -/// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate virtual void SetRedstonePower(bool a_IsPowered) = 0; }; diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 1e8d0e6f0..a79a485a6 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2142,10 +2142,10 @@ bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_Blo case E_BLOCK_DROPPER: case E_BLOCK_DISPENSER: case E_BLOCK_NOTE_BLOCK: - break; + break; default: - // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out - return false; + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; } if (a_Callback.Item((cRedstonePoweredEntity *)*itr)) From beab61bbfeca0280bce941c4175837109282c828 Mon Sep 17 00:00:00 2001 From: archshift Date: Wed, 6 Aug 2014 14:16:36 -0700 Subject: [PATCH 114/751] On destroy ender crystal, create bedrock and fire --- src/Entities/EnderCrystal.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Entities/EnderCrystal.cpp b/src/Entities/EnderCrystal.cpp index bf86a6c42..c17bb608e 100644 --- a/src/Entities/EnderCrystal.cpp +++ b/src/Entities/EnderCrystal.cpp @@ -32,9 +32,6 @@ void cEnderCrystal::SpawnOn(cClientHandle & a_ClientHandle) void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk) { UNUSED(a_Dt); - - a_Chunk.SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_FIRE, 0); - // No further processing (physics e.t.c.) is needed } @@ -49,6 +46,9 @@ void cEnderCrystal::KilledBy(TakeDamageInfo & a_TDI) m_World->DoExplosionAt(6.0, GetPosX(), GetPosY(), GetPosZ(), true, esEnderCrystal, this); Destroy(); + + m_World->SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_BEDROCK, 0); + m_World->SetBlock(POSX_TOINT, POSY_TOINT + 1, POSZ_TOINT, E_BLOCK_FIRE, 0); } From 4271d719b68521f91770574b3064525512116670 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 7 Aug 2014 01:07:32 +0200 Subject: [PATCH 115/751] Added SetDoDaylightCycle() and IsDaylightCycleEnabled() to cWorld. I need this for a GameRule plugin. --- src/ClientHandle.cpp | 11 ++++++++- src/ClientHandle.h | 2 +- src/World.cpp | 53 ++++++++++++++++++++++++++++---------------- src/World.h | 14 +++++++++++- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 3e046f38d..286c17513 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -342,7 +342,16 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, } // Send time - m_Protocol->SendTimeUpdate(World->GetWorldAge(), World->GetTimeOfDay()); + Int64 TimeOfDay = World->GetTimeOfDay(); + if (!World->IsDaylightCycleEnabled()) + { + TimeOfDay *= -1; + if (TimeOfDay == 0) + { + TimeOfDay = -1; + } + } + m_Protocol->SendTimeUpdate(World->GetWorldAge(), TimeOfDay); // Send contents of the inventory window m_Protocol->SendWholeInventory(*m_Player->GetWindow()); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index ee1db3155..1bf397ad2 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -179,7 +179,7 @@ public: void SendTabCompletionResults(const AStringVector & a_Results); void SendTeleportEntity (const cEntity & a_Entity); void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); - void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); + void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); // tolua_export void SendUnloadChunk (int a_ChunkX, int a_ChunkZ); void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); diff --git a/src/World.cpp b/src/World.cpp index d2213d1e5..7ed8bc1e4 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -243,6 +243,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin #endif m_Dimension(a_Dimension), m_IsSpawnExplicitlySet(false), + m_DoDaylightCycle(true), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), m_WorldAge(0), @@ -827,28 +828,32 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec) { SetChunkData(**itr); } // for itr - SetChunkDataQueue[] - - // We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it + m_WorldAgeSecs += (double)a_Dt / 1000.0; - m_TimeOfDaySecs += (double)a_Dt / 1000.0; - - // Wrap time of day each 20 minutes (1200 seconds) - if (m_TimeOfDaySecs > 1200.0) - { - m_TimeOfDaySecs -= 1200.0; - } - m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0); - m_TimeOfDay = (Int64)(m_TimeOfDaySecs * 20.0); - // Updates the sky darkness based on current time of day - UpdateSkyDarkness(); - - // Broadcast time update every 40 ticks (2 seconds) - if (m_LastTimeUpdate < m_WorldAge - 40) + if (m_DoDaylightCycle) { - BroadcastTimeUpdate(); - m_LastTimeUpdate = m_WorldAge; + // We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it + m_TimeOfDaySecs += (double)a_Dt / 1000.0; + + // Wrap time of day each 20 minutes (1200 seconds) + if (m_TimeOfDaySecs > 1200.0) + { + m_TimeOfDaySecs -= 1200.0; + } + + m_TimeOfDay = (Int64)(m_TimeOfDaySecs * 20.0); + + // Updates the sky darkness based on current time of day + UpdateSkyDarkness(); + + // Broadcast time update every 40 ticks (2 seconds) + if (m_LastTimeUpdate < m_WorldAge - 40) + { + BroadcastTimeUpdate(); + m_LastTimeUpdate = m_WorldAge; + } } // Add entities waiting in the queue to be added: @@ -2243,6 +2248,16 @@ void cWorld::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { + int TimeOfDay = m_TimeOfDay; + if (!m_DoDaylightCycle) + { + TimeOfDay *= -1; + if (TimeOfDay == 0) + { + TimeOfDay = -1; + } + } + cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { @@ -2251,7 +2266,7 @@ void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { continue; } - ch->SendTimeUpdate(m_WorldAge, m_TimeOfDay); + ch->SendTimeUpdate(m_WorldAge, TimeOfDay); } } diff --git a/src/World.h b/src/World.h index 90b798e8e..8ddc69118 100644 --- a/src/World.h +++ b/src/World.h @@ -145,7 +145,17 @@ public: // tolua_begin int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } - + + /** Is the daylight cyclus enabled? */ + virtual bool IsDaylightCycleEnabled(void) const { return m_DoDaylightCycle; } + + /** Sets the daylight cyclus to true/false. */ + virtual void SetDoDaylightCycle(bool a_DoDaylightCycle) + { + m_DoDaylightCycle = a_DoDaylightCycle; + BroadcastTimeUpdate(); + } + virtual Int64 GetWorldAge (void) const override { return m_WorldAge; } virtual Int64 GetTimeOfDay(void) const override { return m_TimeOfDay; } @@ -158,6 +168,7 @@ public: { m_TimeOfDay = a_TimeOfDay; m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0; + UpdateSkyDarkness(); BroadcastTimeUpdate(); } @@ -868,6 +879,7 @@ private: bool m_BroadcastDeathMessages; bool m_BroadcastAchievementMessages; + bool m_DoDaylightCycle; // Is the daylight cyclus enabled? double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs From 0c622522ea52ed07aa12a25827b498acd290b531 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 7 Aug 2014 01:08:31 +0200 Subject: [PATCH 116/751] Removed debug message. --- src/Bindings/ManualBindings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 9ba1501c5..8e6156d97 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -507,7 +507,6 @@ static int tolua_DoWithXYZ(lua_State* tolua_S) int ItemX = ((int)tolua_tonumber(tolua_S, 2, 0)); int ItemY = ((int)tolua_tonumber(tolua_S, 3, 0)); int ItemZ = ((int)tolua_tonumber(tolua_S, 4, 0)); - LOG("x %i y %i z %i", ItemX, ItemY, ItemZ); if (!lua_isfunction( tolua_S, 5)) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #4"); From a73c85d7eb8181b3792f19675c29f43bd8c0b738 Mon Sep 17 00:00:00 2001 From: Howaner Date: Thu, 7 Aug 2014 02:42:42 +0200 Subject: [PATCH 117/751] Fixed nether wart digging. Fixes #1265 --- src/BlockInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 4bc3fbbdc..a59229f87 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -294,6 +294,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_OneHitDig = true; a_Info[E_BLOCK_LILY_PAD ].m_OneHitDig = true; a_Info[E_BLOCK_MELON_STEM ].m_OneHitDig = true; + a_Info[E_BLOCK_NETHER_WART ].m_OneHitDig = true; a_Info[E_BLOCK_POTATOES ].m_OneHitDig = true; a_Info[E_BLOCK_PUMPKIN_STEM ].m_OneHitDig = true; a_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_OneHitDig = true; From 670e94bfeb62a51ca64ffaa0e45086e1ca91057c Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 09:56:28 +0200 Subject: [PATCH 118/751] 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 119/751] 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 120/751] 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 3d68466ab03c3f7f2879451a57acba65ed5b197f Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 8 Aug 2014 18:55:05 +0200 Subject: [PATCH 121/751] Send the old slab to the client when the interact cancelled. --- src/Blocks/BlockSlab.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 214445eda..28fdbe7af 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -110,6 +110,17 @@ public: { return ((a_BlockType == E_BLOCK_WOODEN_SLAB) || (a_BlockType == E_BLOCK_STONE_SLAB)); } + + + virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + { + if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player->GetEquippedItem().m_ItemType != (short)m_BlockType)) + { + return; + } + + a_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); + } /// Converts the single-slab blocktype to its equivalent double-slab blocktype From 89333c5870efb438a38786fd67b82daff0482d9a Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 21:30:47 +0200 Subject: [PATCH 122/751] 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 ebfc0fdc676eb4e0e99fc59ab6da6919fa2ef471 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 8 Aug 2014 22:04:53 +0200 Subject: [PATCH 123/751] Added comment. --- src/Blocks/BlockSlab.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 28fdbe7af..49f00c88c 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -119,6 +119,9 @@ public: return; } + /* Sends the slab back to the client. + The normal back sending adds the block face to the locations, but this don't work because the Y-Coordinate with the block face + is one higher than the real slab position. */ a_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } From 32e1e9a5536f92d074d51cca207f21c372973629 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 8 Aug 2014 18:38:20 +0200 Subject: [PATCH 124/751] Renamed m_DoDaylightCycle to m_CycleDaylight. --- src/World.cpp | 6 +++--- src/World.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index 7ed8bc1e4..ab46e886c 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -243,7 +243,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin #endif m_Dimension(a_Dimension), m_IsSpawnExplicitlySet(false), - m_DoDaylightCycle(true), + m_CycleDaylight(true), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), m_WorldAge(0), @@ -832,7 +832,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec) m_WorldAgeSecs += (double)a_Dt / 1000.0; m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0); - if (m_DoDaylightCycle) + if (m_CycleDaylight) { // We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it m_TimeOfDaySecs += (double)a_Dt / 1000.0; @@ -2249,7 +2249,7 @@ void cWorld::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { int TimeOfDay = m_TimeOfDay; - if (!m_DoDaylightCycle) + if (!m_CycleDaylight) { TimeOfDay *= -1; if (TimeOfDay == 0) diff --git a/src/World.h b/src/World.h index 8ddc69118..4e85087fc 100644 --- a/src/World.h +++ b/src/World.h @@ -147,12 +147,12 @@ public: int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } /** Is the daylight cyclus enabled? */ - virtual bool IsDaylightCycleEnabled(void) const { return m_DoDaylightCycle; } + virtual bool IsDaylightCycleEnabled(void) const { return m_CycleDaylight; } /** Sets the daylight cyclus to true/false. */ - virtual void SetDoDaylightCycle(bool a_DoDaylightCycle) + virtual void SetDoDaylightCycle(bool a_CycleDaylight) { - m_DoDaylightCycle = a_DoDaylightCycle; + m_CycleDaylight = a_CycleDaylight; BroadcastTimeUpdate(); } @@ -879,7 +879,7 @@ private: bool m_BroadcastDeathMessages; bool m_BroadcastAchievementMessages; - bool m_DoDaylightCycle; // Is the daylight cyclus enabled? + bool m_CycleDaylight; // Is the daylight cyclus enabled? double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs From 3df7d8446c4d5387475a8d6c2f1c3d5ab28b28eb Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 8 Aug 2014 23:11:42 +0200 Subject: [PATCH 125/751] 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 126/751] 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 127/751] 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 128/751] 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 129/751] 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 130/751] 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 131/751] 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 dcef688ccc0ae60b001ce40fd591a2dfafbac294 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 22:34:59 +0200 Subject: [PATCH 132/751] 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 b0dedb01977fe4cd7ebd51db5784d8ca415f1567 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 9 Aug 2014 22:54:43 +0200 Subject: [PATCH 133/751] 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 8e6156d97..6b40cece8 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 5eb5411f1e9f3683e8ecb6448877ba6cf34b2dbf Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 10 Aug 2014 11:06:04 +0200 Subject: [PATCH 134/751] Removed an old and outdated comment. --- src/Generating/FinishGen.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index e8324095e..eb57a5faa 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -484,8 +484,6 @@ int cFinishGenSingleTopBlock::GetNumToGen(const cChunkDef::BiomeMap & a_BiomeMap void cFinishGenSingleTopBlock::GenFinish(cChunkDesc & a_ChunkDesc) { - // Add Lilypads on top of water surface in Swampland - int NumToGen = GetNumToGen(a_ChunkDesc.GetBiomeMap()); int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); From ecfae286064b4a8fcf6e4df38c09e8055e83de33 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 10 Aug 2014 11:40:33 +0200 Subject: [PATCH 135/751] Changed cStructGenOreNests to take a list of ores + the block to replace. --- src/Generating/ComposableGenerator.cpp | 52 ++++++++++++++++++++++- src/Generating/StructGen.cpp | 58 +++++--------------------- src/Generating/StructGen.h | 26 ++++++++++-- 3 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index cedb9aeb7..79a92171f 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -400,7 +400,57 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "OreNests") == 0) { - m_FinishGens.push_back(new cStructGenOreNests(Seed)); + cStructGenOreNests::OreList Ores; + + // Coal vein + cStructGenOreNests::OreInfo CoalVein; + CoalVein.BlockType = E_BLOCK_COAL_ORE; + CoalVein.MaxHeight = 127; + CoalVein.NumNests = 50; + CoalVein.NestSize = 10; + Ores.push_back(CoalVein); + + // Iron vein + cStructGenOreNests::OreInfo IronVein; + IronVein.BlockType = E_BLOCK_IRON_ORE; + IronVein.MaxHeight = 64; + IronVein.NumNests = 14; + IronVein.NestSize = 6; + Ores.push_back(IronVein); + + // Gold vein + cStructGenOreNests::OreInfo GoldVein; + GoldVein.BlockType = E_BLOCK_GOLD_ORE; + GoldVein.MaxHeight = 32; + GoldVein.NumNests = 2; + GoldVein.NestSize = 6; + Ores.push_back(GoldVein); + + // Redstone vein + cStructGenOreNests::OreInfo RedstoneVein; + RedstoneVein.BlockType = E_BLOCK_REDSTONE_ORE; + RedstoneVein.MaxHeight = 16; + RedstoneVein.NumNests = 4; + RedstoneVein.NestSize = 6; + Ores.push_back(RedstoneVein); + + // Lapis vein + cStructGenOreNests::OreInfo LapisVein; + LapisVein.BlockType = E_BLOCK_LAPIS_ORE; + LapisVein.MaxHeight = 30; + LapisVein.NumNests = 2; + LapisVein.NestSize = 5; + Ores.push_back(LapisVein); + + // Diamond vein + cStructGenOreNests::OreInfo DiamondVein; + DiamondVein.BlockType = E_BLOCK_DIAMOND_ORE; + DiamondVein.MaxHeight = 15; + DiamondVein.NumNests = 1; + DiamondVein.NestSize = 4; + Ores.push_back(DiamondVein); + + m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); } else if (NoCaseCompare(*itr, "POCPieces") == 0) { diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index f7e609353..1a43f2b2e 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -12,45 +12,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// cStructGenOreNests configuration: - -const int MAX_HEIGHT_COAL = 127; -const int NUM_NESTS_COAL = 50; -const int NEST_SIZE_COAL = 10; - -const int MAX_HEIGHT_IRON = 64; -const int NUM_NESTS_IRON = 14; -const int NEST_SIZE_IRON = 6; - -const int MAX_HEIGHT_REDSTONE = 16; -const int NUM_NESTS_REDSTONE = 4; -const int NEST_SIZE_REDSTONE = 6; - -const int MAX_HEIGHT_GOLD = 32; -const int NUM_NESTS_GOLD = 2; -const int NEST_SIZE_GOLD = 6; - -const int MAX_HEIGHT_DIAMOND = 15; -const int NUM_NESTS_DIAMOND = 1; -const int NEST_SIZE_DIAMOND = 4; - -const int MAX_HEIGHT_LAPIS = 30; -const int NUM_NESTS_LAPIS = 2; -const int NEST_SIZE_LAPIS = 5; - -const int MAX_HEIGHT_DIRT = 127; -const int NUM_NESTS_DIRT = 20; -const int NEST_SIZE_DIRT = 32; - -const int MAX_HEIGHT_GRAVEL = 70; -const int NUM_NESTS_GRAVEL = 15; -const int NEST_SIZE_GRAVEL = 32; - - - - - //////////////////////////////////////////////////////////////////////////////// // cStructGenTrees: @@ -311,14 +272,15 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_COAL_ORE, MAX_HEIGHT_COAL, NUM_NESTS_COAL, NEST_SIZE_COAL, BlockTypes, 1); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_IRON_ORE, MAX_HEIGHT_IRON, NUM_NESTS_IRON, NEST_SIZE_IRON, BlockTypes, 2); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_REDSTONE_ORE, MAX_HEIGHT_REDSTONE, NUM_NESTS_REDSTONE, NEST_SIZE_REDSTONE, BlockTypes, 3); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_GOLD_ORE, MAX_HEIGHT_GOLD, NUM_NESTS_GOLD, NEST_SIZE_GOLD, BlockTypes, 4); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIAMOND_ORE, MAX_HEIGHT_DIAMOND, NUM_NESTS_DIAMOND, NEST_SIZE_DIAMOND, BlockTypes, 5); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_LAPIS_ORE, MAX_HEIGHT_LAPIS, NUM_NESTS_LAPIS, NEST_SIZE_LAPIS, BlockTypes, 6); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIRT, MAX_HEIGHT_DIRT, NUM_NESTS_DIRT, NEST_SIZE_DIRT, BlockTypes, 10); - GenerateOre(ChunkX, ChunkZ, E_BLOCK_GRAVEL, MAX_HEIGHT_GRAVEL, NUM_NESTS_GRAVEL, NEST_SIZE_GRAVEL, BlockTypes, 11); + + int seq = 1; + + // Generate the ores from the ore list. + for (OreList::iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr) + { + GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, seq); + seq++; + } } @@ -376,7 +338,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore } int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ); - if (a_BlockTypes[Index] == E_BLOCK_STONE) + if (a_BlockTypes[Index] == m_ToReplace) { a_BlockTypes[Index] = a_OreType; } diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h index 9176bc192..e2fe8bc1a 100644 --- a/src/Generating/StructGen.h +++ b/src/Generating/StructGen.h @@ -76,11 +76,29 @@ class cStructGenOreNests : public cFinishGen { public: - cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {} - + struct OreInfo + { + BLOCKTYPE BlockType; // The type of the nest. + int MaxHeight; // The highest possible a nest can occur + int NumNests; // How many nests per chunk + int NestSize; // The amount of blocks a nest can have. + }; + + typedef std::vector OreList; + + cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) : + m_Noise(a_Seed), + m_Seed(a_Seed), + m_OreList(a_OreList), + m_ToReplace(a_ToReplace) + {} + protected: - cNoise m_Noise; - int m_Seed; + cNoise m_Noise; + int m_Seed; + + OreList m_OreList; // A list of possible ores. + BLOCKTYPE m_ToReplace; // cFinishGen override: virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; From 0ac3c67a21ae6fbd060322d65fcdad4f98148567 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 10 Aug 2014 11:48:05 +0200 Subject: [PATCH 136/751] Added NetherOreNests. It generates Nether Quarts. --- src/Generating/ComposableGenerator.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 79a92171f..1ae86a29f 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -398,6 +398,21 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12); m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth)); } + else if (NoCaseCompare(*itr, "NetherOreNests") == 0) + { + cStructGenOreNests::OreList Ores; + + // Quarts vein + cStructGenOreNests::OreInfo QuartsVein; + QuartsVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE; + QuartsVein.MaxHeight = 255; + QuartsVein.NumNests = 80; + QuartsVein.NestSize = 8; + Ores.push_back(QuartsVein); + + m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK)); + + } else if (NoCaseCompare(*itr, "OreNests") == 0) { cStructGenOreNests::OreList Ores; From e529401dbb6d9c6de3b5e81b3308a478fe1a36db Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 10 Aug 2014 11:57:05 +0200 Subject: [PATCH 137/751] Added NaturalPatches generator It generates gravel and dirt. --- src/Generating/ComposableGenerator.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 1ae86a29f..58ad8fc2e 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -387,6 +387,28 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)); } + else if (NoCaseCompare(*itr, "NaturalPatches") == 0) + { + cStructGenOreNests::OreList Ores; + + // Dirt vein + cStructGenOreNests::OreInfo DirtVein; + DirtVein.BlockType = E_BLOCK_DIRT; + DirtVein.MaxHeight = 127; + DirtVein.NumNests = 20; + DirtVein.NestSize = 32; + Ores.push_back(DirtVein); + + // Gravel vein + cStructGenOreNests::OreInfo GravelVein; + GravelVein.BlockType = E_BLOCK_DIRT; + GravelVein.MaxHeight = 127; + GravelVein.NumNests = 20; + GravelVein.NestSize = 32; + Ores.push_back(GravelVein); + + m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE)); + } else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) { m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); From cccc321384be18d4ac75e83abf3ce4d19a2a3d56 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 10 Aug 2014 16:46:03 +0200 Subject: [PATCH 138/751] Renamed functions. --- src/World.cpp | 6 +++--- src/World.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/World.cpp b/src/World.cpp index ab46e886c..dc1d9fedf 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -243,7 +243,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin #endif m_Dimension(a_Dimension), m_IsSpawnExplicitlySet(false), - m_CycleDaylight(true), + m_IsDaylightCycleEnabled(true), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), m_WorldAge(0), @@ -832,7 +832,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec) m_WorldAgeSecs += (double)a_Dt / 1000.0; m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0); - if (m_CycleDaylight) + if (m_IsDaylightCycleEnabled) { // We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it m_TimeOfDaySecs += (double)a_Dt / 1000.0; @@ -2249,7 +2249,7 @@ void cWorld::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { int TimeOfDay = m_TimeOfDay; - if (!m_CycleDaylight) + if (!m_IsDaylightCycleEnabled) { TimeOfDay *= -1; if (TimeOfDay == 0) diff --git a/src/World.h b/src/World.h index 4e85087fc..6df1758e9 100644 --- a/src/World.h +++ b/src/World.h @@ -147,12 +147,12 @@ public: int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } /** Is the daylight cyclus enabled? */ - virtual bool IsDaylightCycleEnabled(void) const { return m_CycleDaylight; } + virtual bool IsDaylightCycleEnabled(void) const { return m_IsDaylightCycleEnabled; } /** Sets the daylight cyclus to true/false. */ - virtual void SetDoDaylightCycle(bool a_CycleDaylight) + virtual void SetDaylightCycleEnabled(bool a_IsDaylightCycleEnabled) { - m_CycleDaylight = a_CycleDaylight; + m_IsDaylightCycleEnabled = a_IsDaylightCycleEnabled; BroadcastTimeUpdate(); } @@ -879,7 +879,7 @@ private: bool m_BroadcastDeathMessages; bool m_BroadcastAchievementMessages; - bool m_CycleDaylight; // Is the daylight cyclus enabled? + bool m_IsDaylightCycleEnabled; double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs From f90078c09ff576d3f8af1554872c53afbdcd6fe0 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 10 Aug 2014 16:48:20 +0200 Subject: [PATCH 139/751] Added IsDaylightCycleEnabled saving. --- src/World.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/World.cpp b/src/World.cpp index dc1d9fedf..0ae7f80a6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -577,6 +577,7 @@ void cWorld::Start(void) m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); + m_IsDaylightCycleEnabled = IniFile.GetValueSetB("General", "IsDaylightCycleEnabled", true); int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); int Weather = IniFile.GetValueSetI("General", "Weather", (int)m_Weather); @@ -798,6 +799,7 @@ void cWorld::Stop(void) IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel); IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled); IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes); + IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled); IniFile.SetValueI("General", "Weather", (int)m_Weather); IniFile.SetValueI("General", "TimeInTicks", m_TimeOfDay); IniFile.WriteFile(m_IniFileName); From ae611563919d123a93d6aab0eaf20c7423acce23 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 10 Aug 2014 17:08:22 +0200 Subject: [PATCH 140/751] Fixed swing arm animation when you ate. --- src/Entities/Player.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index d1d7349a6..8fa060a5d 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -601,7 +601,6 @@ void cPlayer::FinishEating(void) // Send the packets: m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted); - m_World->BroadcastEntityAnimation(*this, 0); m_World->BroadcastEntityMetadata(*this); // consume the item: @@ -619,8 +618,8 @@ void cPlayer::FinishEating(void) // if the food is mushroom soup, return a bowl to the inventory if (Item.m_ItemType == E_ITEM_MUSHROOM_SOUP) { - cItem emptyBowl(E_ITEM_BOWL, 1, 0, ""); - GetInventory().AddItem(emptyBowl, true, true); + cItem EmptyBowl(E_ITEM_BOWL); + GetInventory().AddItem(EmptyBowl, true, true); } } @@ -631,7 +630,6 @@ void cPlayer::FinishEating(void) void cPlayer::AbortEating(void) { m_EatingFinishTick = -1; - m_World->BroadcastEntityAnimation(*this, 0); m_World->BroadcastEntityMetadata(*this); } From 938bf1df69ae88ecdd85029d20bfd09d4fbf7618 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 10 Aug 2014 17:12:08 +0200 Subject: [PATCH 141/751] Changed comment. --- src/Blocks/BlockSlab.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 49f00c88c..e67f0e8b3 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -119,9 +119,7 @@ public: return; } - /* Sends the slab back to the client. - The normal back sending adds the block face to the locations, but this don't work because the Y-Coordinate with the block face - is one higher than the real slab position. */ + // Sends the slab back to the client. It's to refuse a doubleslab placement. a_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); } From 42bad0edec58f42e4072360c52870d3be9ced3c5 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 10 Aug 2014 20:06:03 +0200 Subject: [PATCH 142/751] Added a comment and simplified code. --- src/ClientHandle.cpp | 9 +++------ src/World.cpp | 7 ++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 286c17513..37d7edbc1 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -341,15 +341,12 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, m_Protocol->SendWeather(World->GetWeather()); } - // Send time + // Send time: Int64 TimeOfDay = World->GetTimeOfDay(); if (!World->IsDaylightCycleEnabled()) { - TimeOfDay *= -1; - if (TimeOfDay == 0) - { - TimeOfDay = -1; - } + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + TimeOfDay = std::min(-TimeOfDay, -1); } m_Protocol->SendTimeUpdate(World->GetWorldAge(), TimeOfDay); diff --git a/src/World.cpp b/src/World.cpp index 0ae7f80a6..dcca0519e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2253,11 +2253,8 @@ void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) int TimeOfDay = m_TimeOfDay; if (!m_IsDaylightCycleEnabled) { - TimeOfDay *= -1; - if (TimeOfDay == 0) - { - TimeOfDay = -1; - } + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + TimeOfDay = std::min(-TimeOfDay, -1); } cCSLock Lock(m_CSPlayers); From 806d0936dc94f235858ffe1772a6215f86c5d000 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 19:34:11 +0100 Subject: [PATCH 143/751] First Implementatation of new Loggin framework --- SetFlags.cmake | 2 + src/Bindings/LuaFunctions.h | 2 +- src/Bindings/ManualBindings.cpp | 10 +- src/CMakeLists.txt | 6 +- src/CompositeChat.cpp | 24 +-- src/CompositeChat.h | 2 +- src/Globals.h | 2 +- src/MCLogger.cpp | 267 -------------------------------- src/MCLogger.h | 95 ------------ src/OSSupport/File.cpp | 5 +- src/OSSupport/File.h | 3 +- src/Root.cpp | 26 +++- src/Root.h | 2 - src/StringUtils.h | 1 - src/main.cpp | 2 + 15 files changed, 51 insertions(+), 398 deletions(-) delete mode 100644 src/MCLogger.cpp delete mode 100644 src/MCLogger.h diff --git a/SetFlags.cmake b/SetFlags.cmake index a5a61eaa4..0e2e0c277 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -1,3 +1,5 @@ + + macro (add_flags_lnk FLAGS) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}") diff --git a/src/Bindings/LuaFunctions.h b/src/Bindings/LuaFunctions.h index 2ea37d7a4..6a645ed53 100644 --- a/src/Bindings/LuaFunctions.h +++ b/src/Bindings/LuaFunctions.h @@ -1,6 +1,6 @@ #pragma once -#include "../MCLogger.h" +#include "LogDispacher.h" #include // tolua_begin diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 9ba1501c5..d792cd0ee 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -168,7 +168,7 @@ static AString GetLogMessage(lua_State * tolua_S) static int tolua_LOG(lua_State * tolua_S) { // If the param is a cCompositeChat, read the log level from it: - cMCLogger::eLogLevel LogLevel = cMCLogger::llRegular; + Logger::eLogLevel LogLevel = Logger::llRegular; tolua_Error err; if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) { @@ -176,7 +176,7 @@ static int tolua_LOG(lua_State * tolua_S) } // Log the message: - cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); + Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); return 0; } @@ -186,7 +186,7 @@ static int tolua_LOG(lua_State * tolua_S) static int tolua_LOGINFO(lua_State * tolua_S) { - cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llInfo); + Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llInfo); return 0; } @@ -196,7 +196,7 @@ static int tolua_LOGINFO(lua_State * tolua_S) static int tolua_LOGWARN(lua_State * tolua_S) { - cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llWarning); + Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llWarning); return 0; } @@ -206,7 +206,7 @@ static int tolua_LOGWARN(lua_State * tolua_S) static int tolua_LOGERROR(lua_State * tolua_S) { - cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llError); + Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llError); return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db9c61082..0feee4fcb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 2.8.2) project (MCServer) + include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/jsoncpp/include") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") @@ -41,8 +42,9 @@ SET (SRCS LightingThread.cpp LineBlockTracer.cpp LinearInterpolation.cpp + Listeners.cpp Log.cpp - MCLogger.cpp + LogDispacher.cpp Map.cpp MapManager.cpp MobCensus.cpp @@ -108,7 +110,7 @@ SET (HDRS LinearInterpolation.h LinearUpscale.h Log.h - MCLogger.h + LogDispacher.h Map.h MapManager.h Matrix4.h diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index f1a797897..b702447be 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -353,23 +353,23 @@ AString cCompositeChat::ExtractText(void) const -cMCLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) +Logger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) { switch (a_MessageType) { - case mtCustom: return cMCLogger::llRegular; - case mtFailure: return cMCLogger::llWarning; - case mtInformation: return cMCLogger::llInfo; - case mtSuccess: return cMCLogger::llRegular; - case mtWarning: return cMCLogger::llWarning; - case mtFatal: return cMCLogger::llError; - case mtDeath: return cMCLogger::llRegular; - case mtPrivateMessage: return cMCLogger::llRegular; - case mtJoin: return cMCLogger::llRegular; - case mtLeave: return cMCLogger::llRegular; + case mtCustom: return Logger::llRegular; + case mtFailure: return Logger::llWarning; + case mtInformation: return Logger::llInfo; + case mtSuccess: return Logger::llRegular; + case mtWarning: return Logger::llWarning; + case mtFatal: return Logger::llError; + case mtDeath: return Logger::llRegular; + case mtPrivateMessage: return Logger::llRegular; + case mtJoin: return Logger::llRegular; + case mtLeave: return Logger::llRegular; } ASSERT(!"Unhandled MessageType"); - return cMCLogger::llError; + return Logger::llError; } diff --git a/src/CompositeChat.h b/src/CompositeChat.h index 1ad196f1d..cc7c446c3 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -196,7 +196,7 @@ public: /** Converts the MessageType to a LogLevel value. Used by the logging bindings when logging a cCompositeChat object. */ - static cMCLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); + static Logger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); protected: /** All the parts that */ diff --git a/src/Globals.h b/src/Globals.h index 60ee456c9..ae7a68e7f 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -249,7 +249,7 @@ template class SizeChecker; #include "OSSupport/Event.h" #include "OSSupport/Thread.h" #include "OSSupport/File.h" - #include "MCLogger.h" + #include "LogDispacher.h" #else // Logging functions void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2); diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp deleted file mode 100644 index 044e83937..000000000 --- a/src/MCLogger.cpp +++ /dev/null @@ -1,267 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include -#include "Log.h" - - - - - -cMCLogger * cMCLogger::s_MCLogger = NULL; - -#ifdef _WIN32 - #include // Needed for _isatty(), not available on Linux - - HANDLE g_Console = GetStdHandle(STD_OUTPUT_HANDLE); - WORD g_DefaultConsoleAttrib = 0x07; -#elif defined (__linux) && !defined(ANDROID_NDK) - #include // Needed for isatty() on Linux -#endif - - - - - -cMCLogger * cMCLogger::GetInstance(void) -{ - return s_MCLogger; -} - - - - - -cMCLogger::cMCLogger(void): - m_ShouldColorOutput(false) -{ - AString FileName; - Printf(FileName, "LOG_%d.txt", (int)time(NULL)); - InitLog(FileName); -} - - - - - -cMCLogger::cMCLogger(const AString & a_FileName) -{ - InitLog(a_FileName); -} - - - - - -cMCLogger::~cMCLogger() -{ - m_Log->Log("--- Stopped Log ---\n"); - delete m_Log; - m_Log = NULL; - if (this == s_MCLogger) - { - s_MCLogger = NULL; - } -} - - - - - -void cMCLogger::InitLog(const AString & a_FileName) -{ - m_Log = new cLog(a_FileName); - m_Log->Log("--- Started Log ---\n"); - - s_MCLogger = this; - - #ifdef _WIN32 - // See whether we are writing to a console the default console attrib: - m_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); - if (m_ShouldColorOutput) - { - CONSOLE_SCREEN_BUFFER_INFO sbi; - GetConsoleScreenBufferInfo(g_Console, &sbi); - g_DefaultConsoleAttrib = sbi.wAttributes; - } - #elif defined (__linux) && !defined(ANDROID_NDK) - m_ShouldColorOutput = isatty(fileno(stdout)); - // TODO: Check if the terminal supports colors, somehow? - #endif -} - - - - - -void cMCLogger::LogSimple(const char * a_Text, eLogLevel a_LogLevel) -{ - switch (a_LogLevel) - { - case llRegular: - { - LOG("%s", a_Text); - break; - } - case llInfo: - { - LOGINFO("%s", a_Text); - break; - } - case llWarning: - { - LOGWARN("%s", a_Text); - break; - } - case llError: - { - LOGERROR("%s", a_Text); - break; - } - } -} - - - - - -void cMCLogger::Log(const char * a_Format, va_list a_ArgList) -{ - cCSLock Lock(m_CriticalSection); - SetColor(csRegular); - m_Log->Log(a_Format, a_ArgList); - ResetColor(); - puts(""); -} - - - - - -void cMCLogger::Info(const char * a_Format, va_list a_ArgList) -{ - cCSLock Lock(m_CriticalSection); - SetColor(csInfo); - m_Log->Log(a_Format, a_ArgList); - ResetColor(); - puts(""); -} - - - - - -void cMCLogger::Warn(const char * a_Format, va_list a_ArgList) -{ - cCSLock Lock(m_CriticalSection); - SetColor(csWarning); - m_Log->Log(a_Format, a_ArgList); - ResetColor(); - puts(""); -} - - - - - -void cMCLogger::Error(const char * a_Format, va_list a_ArgList) -{ - cCSLock Lock(m_CriticalSection); - SetColor(csError); - m_Log->Log(a_Format, a_ArgList); - ResetColor(); - puts(""); -} - - - - - -void cMCLogger::SetColor(eColorScheme a_Scheme) -{ - if (!m_ShouldColorOutput) - { - return; - } - #ifdef _WIN32 - WORD Attrib = 0x07; // by default, gray on black - switch (a_Scheme) - { - case csRegular: Attrib = 0x07; break; // Gray on black - case csInfo: Attrib = 0x0e; break; // Yellow on black - case csWarning: Attrib = 0x0c; break; // Read on black - case csError: Attrib = 0xc0; break; // Black on red - default: ASSERT(!"Unhandled color scheme"); - } - SetConsoleTextAttribute(g_Console, Attrib); - #elif defined(__linux) && !defined(ANDROID_NDK) - switch (a_Scheme) - { - case csRegular: printf("\x1b[0m"); break; // Whatever the console default is - case csInfo: printf("\x1b[33;1m"); break; // Yellow on black - case csWarning: printf("\x1b[31;1m"); break; // Red on black - case csError: printf("\x1b[1;33;41;1m"); break; // Yellow on red - default: ASSERT(!"Unhandled color scheme"); - } - #endif -} - - - - - -void cMCLogger::ResetColor(void) -{ - if (!m_ShouldColorOutput) - { - return; - } - #ifdef _WIN32 - SetConsoleTextAttribute(g_Console, g_DefaultConsoleAttrib); - #elif defined(__linux) && !defined(ANDROID_NDK) - printf("\x1b[0m"); - #endif -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// Global functions - -void LOG(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - cMCLogger::GetInstance()->Log( a_Format, argList); - va_end(argList); -} - -void LOGINFO(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - cMCLogger::GetInstance()->Info( a_Format, argList); - va_end(argList); -} - -void LOGWARN(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - cMCLogger::GetInstance()->Warn( a_Format, argList); - va_end(argList); -} - -void LOGERROR(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - cMCLogger::GetInstance()->Error( a_Format, argList); - va_end(argList); -} - - - - diff --git a/src/MCLogger.h b/src/MCLogger.h deleted file mode 100644 index aa3a52d02..000000000 --- a/src/MCLogger.h +++ /dev/null @@ -1,95 +0,0 @@ - -#pragma once - - - - -class cLog; - - - - - -class cMCLogger -{ -public: - enum eLogLevel - { - llRegular, - llInfo, - llWarning, - llError, - }; - // tolua_end - - /** Creates a logger with the default filename, "logs/LOG_.log" */ - cMCLogger(void); - - /** Creates a logger with the specified filename inside "logs" folder */ - cMCLogger(const AString & a_FileName); - - ~cMCLogger(); - - void Log (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Info (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Warn (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Error(const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - - /** Logs the simple text message at the specified log level. */ - void LogSimple(const char * a_Text, eLogLevel a_LogLevel = llRegular); - - static cMCLogger * GetInstance(); -private: - enum eColorScheme - { - csRegular, - csInfo, - csWarning, - csError, - } ; - - cCriticalSection m_CriticalSection; - cLog * m_Log; - static cMCLogger * s_MCLogger; - bool m_ShouldColorOutput; - - - /// Sets the specified color scheme in the terminal (TODO: if coloring available) - void SetColor(eColorScheme a_Scheme); - - /// Resets the color back to whatever is the default in the terminal - void ResetColor(void); - - /// Common initialization for all constructors, creates a logfile with the specified name and assigns s_MCLogger to this - void InitLog(const AString & a_FileName); -}; - - - - - -extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2); -extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2); -extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2); -extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2); - - - - - -// In debug builds, translate LOGD to LOG, otherwise leave it out altogether: -#ifdef _DEBUG - #define LOGD LOG -#else - #define LOGD(...) -#endif // _DEBUG - - - - - -#define LOGWARNING LOGWARN - - - - diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index ff6fb5898..af8a832f6 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -70,6 +70,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) case fmRead: Mode = "rb"; break; case fmWrite: Mode = "wb"; break; case fmReadWrite: Mode = "rb+"; break; + case fmAppend: Mode = "a+"; break; } if (Mode == NULL) { @@ -255,7 +256,7 @@ int cFile::ReadRestOfFile(AString & a_Contents) return -1; } - int DataSize = GetSize() - Tell(); + size_t DataSize = GetSize() - Tell(); // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly a_Contents.assign((size_t)DataSize, '\0'); @@ -459,7 +460,7 @@ int cFile::Printf(const char * a_Fmt, ...) va_start(args, a_Fmt); AppendVPrintf(buf, a_Fmt, args); va_end(args); - return Write(buf.c_str(), (int)buf.length()); + return Write(buf.c_str(), buf.length()); } diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index 2a7ecf0ed..8891511c4 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -62,7 +62,8 @@ public: { fmRead, // Read-only. If the file doesn't exist, object will not be valid fmWrite, // Write-only. If the file already exists, it will be overwritten - fmReadWrite // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning + fmReadWrite, // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning + fmAppend // Write-only. If the file already exists cursor will be moved to the end of the file } ; /** Simple constructor - creates an unopened file object, use Open() to open / create a real file */ diff --git a/src/Root.cpp b/src/Root.cpp index c20cf0d21..72048b631 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -18,6 +18,7 @@ #include "CommandOutput.h" #include "DeadlockDetect.h" #include "OSSupport/Timer.h" +#include "Listeners.h" #include "inifile/iniFile.h" @@ -51,7 +52,6 @@ cRoot::cRoot(void) : m_FurnaceRecipe(NULL), m_WebAdmin(NULL), m_PluginManager(NULL), - m_Log(NULL), m_bStop(false), m_bRestart(false) { @@ -105,10 +105,15 @@ void cRoot::Start(void) HMENU hmenu = GetSystemMenu(hwnd, FALSE); EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling #endif + + Logger::cLoggerListener * consoleLogListener = Logger::MakeConsoleListener(); + Logger::cLoggerListener * fileLogListener = new Logger::cFileListener(); + Logger::GetInstance().AttachListener(consoleLogListener); + Logger::GetInstance().AttachListener(fileLogListener); + + LOG("--- Started Log ---\n"); cDeadlockDetect dd; - delete m_Log; - m_Log = new cMCLogger(); m_bStop = false; while (!m_bStop) @@ -249,8 +254,13 @@ void cRoot::Start(void) delete m_Server; m_Server = NULL; LOG("Shutdown successful!"); } - - delete m_Log; m_Log = NULL; + + LOG("--- Stopped Log ---"); + + Logger::GetInstance().DetachListener(consoleLogListener); + delete consoleLogListener; + Logger::GetInstance().DetachListener(fileLogListener); + delete fileLogListener; } @@ -274,15 +284,15 @@ void cRoot::LoadWorlds(cIniFile & IniFile) m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds - unsigned int KeyNum = IniFile.FindKey("Worlds"); - unsigned int NumWorlds = IniFile.GetNumValues(KeyNum); + int KeyNum = IniFile.FindKey("Worlds"); + int NumWorlds = IniFile.GetNumValues(KeyNum); if (NumWorlds <= 0) { return; } bool FoundAdditionalWorlds = false; - for (unsigned int i = 0; i < NumWorlds; i++) + for (int i = 0; i < NumWorlds; i++) { AString ValueName = IniFile.GetValueName(KeyNum, i); if (ValueName.compare("World") != 0) diff --git a/src/Root.h b/src/Root.h index 1cd175ab4..6840efcbe 100644 --- a/src/Root.h +++ b/src/Root.h @@ -196,8 +196,6 @@ private: cMojangAPI m_MojangAPI; cHTTPServer m_HTTPServer; - cMCLogger * m_Log; - bool m_bStop; bool m_bRestart; diff --git a/src/StringUtils.h b/src/StringUtils.h index 142aaf59b..3d4379352 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -12,7 +12,6 @@ - typedef std::string AString; typedef std::vector AStringVector; typedef std::list AStringList; diff --git a/src/main.cpp b/src/main.cpp index 106233342..e40035538 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -273,6 +273,8 @@ int main( int argc, char **argv) } } // for i - argv[] + Logger::InitiateMultithreading(); + #if !defined(ANDROID_NDK) try #endif From bf0050e066af60b5f4060b298118d74cf84dc299 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 19:44:49 +0100 Subject: [PATCH 144/751] Added forgoten files --- src/Listeners.cpp | 236 +++++++++++++++++++++++++++++++++++++++++++ src/Listeners.h | 21 ++++ src/LogDispacher.cpp | 115 +++++++++++++++++++++ src/LogDispacher.h | 85 ++++++++++++++++ 4 files changed, 457 insertions(+) create mode 100644 src/Listeners.cpp create mode 100644 src/Listeners.h create mode 100644 src/LogDispacher.cpp create mode 100644 src/LogDispacher.h diff --git a/src/Listeners.cpp b/src/Listeners.cpp new file mode 100644 index 000000000..384dcaf91 --- /dev/null +++ b/src/Listeners.cpp @@ -0,0 +1,236 @@ + +#include "Globals.h" + +#include "Listeners.h" + +#if defined(_WIN32) + #include // Needed for _isatty(), not available on Linux +#elif defined(__linux) && !defined(ANDROID_NDK) + #include // Needed for isatty() on Linux +#elif defined(ANDROID_NDK) + #include +#endif + + +namespace Logger +{ + + #if defined(_WIN32) || (defined (__linux) && !defined(ANDROID_NDK)) + class cColouredConsoleListener + : public cLoggerListener + { + + virtual void SetLogColour(eLogLevel a_LogLevel) = 0; + virtual void SetDefaultLogColour() = 0; + + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + SetLogColour(a_LogLevel); + puts(a_Message.c_str()); + SetDefaultLogColour(); + } + }; + #endif + + #ifdef _WIN32 + class cWindowsConsoleListener + : public cColouredConsoleListener + { + public: + cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) : + m_Console(a_Console), + m_DefaultConsoleAttrib(a_DefaultConsoleAttrib) + { + } + + #ifdef DEBUG + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + cColouredConsoleListener::Log(a_Message, a_LogLevel); + // In a Windows Debug build, output the log to debug console as well: + OutputDebugStringA(a_Message.c_str()); + } + #endif // _WIN32 + + + virtual void SetLogColour(eLogLevel a_LogLevel) override + { + // by default, gray on black + WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + switch (a_LogLevel) + { + case llRegular: + // Gray on black + Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + case llInfo: + // Yellow on black + Attrib = FOREGROUND_GREEN | ; + break; + case llWarning: + // Red on black + Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case llError: + // Black on red + Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; + break; + } + SetConsoleTextAttribute(m_Console, Attrib); + } + virtual void SetDefaultLogColour() override + { + SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); + } + private: + HANDLE m_Console; + WORD m_DefaultConsoleAttrib; + }; + #elif defined (__linux) && !defined(ANDROID_NDK) + class cLinuxConsoleListener + : public cColouredConsoleListener + { + public: + virtual void SetLogColour(eLogLevel a_LogLevel) override + { + switch (a_LogLevel) + { + case llRegular: + // Whatever the console default is + printf("\x1b[0m"); + break; + case llInfo: + // Yellow on black + printf("\x1b[33;1m"); + break; + case llWarning: + // Red on black + printf("\x1b[31;1m"); + break; + case llError: + // Yellow on red + printf("\x1b[1;33;41;1m"); + break; + } + } + virtual void SetDefaultLogColour() override + { + // Whatever the console default is + printf("\x1b[0m"); + } + }; + #elif defined(ANDROID_NDK) + class cAndroidConsoleListener + : public cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + android_LogPriority AndroidLogLevel; + switch (a_LogLevel) + { + case llRegular: + AndroidLogLevel = ANDROID_LOG_VERBOSE; + break; + case llInfo: + AndroidLogLevel = ANDROID_LOG_INFO; + break; + case llWarning: + AndroidLogLevel = ANDROID_LOG_WARNING; + break; + case llError: + AndroidLogLevel = ANDROID_LOG_ERROR; + break; + } + __android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str()); + } + }; + #endif + + class cVanillaCPPConsoleListener + : public cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + AString LogLevelString; + switch (a_LogLevel) + { + case llRegular: + LogLevelString = "Log"; + break; + case llInfo: + LogLevelString = "Info"; + break; + case llWarning: + LogLevelString = "Warning"; + break; + case llError: + LogLevelString = "Error"; + break; + } + printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + } + }; + + + + cLoggerListener * MakeConsoleListener() + { + #ifdef _WIN32 + // See whether we are writing to a console the default console attrib: + bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); + if (ShouldColorOutput) + { + CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE Console = getStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(Console, &sbi); + WORD DefaultConsoleAttrib = sbi.wAttributes; + return new cWindowsConsoleListener(Console, DefaultConsoleAttrib); + } else { + return new cVanillaCPPConsoleListener(); + } + + #elif defined (__linux) && !defined(ANDROID_NDK) + // TODO: lookup terminal in terminfo + if (isatty(fileno(stdout))) + { + return new cLinuxConsoleListener(); + } else { + return new cVanillaCPPConsoleListener(); + } + #else + return new cVanillaCPPConsoleListener(); + #endif + } + + cFileListener::cFileListener() + { + cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); + AString FileName; + FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL)); + m_File.Open(FileName, cFile::fmAppend); + } + + void cFileListener::Log(AString a_Message, eLogLevel a_LogLevel) + { + AString LogLevelString; + switch (a_LogLevel) + { + case llRegular: + LogLevelString = "Log"; + break; + case llInfo: + LogLevelString = "Info"; + break; + case llWarning: + LogLevelString = "Warning"; + break; + case llError: + LogLevelString = "Error"; + break; + } + m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + } + +} diff --git a/src/Listeners.h b/src/Listeners.h new file mode 100644 index 000000000..bc29d0c06 --- /dev/null +++ b/src/Listeners.h @@ -0,0 +1,21 @@ + +#include "LogDispacher.h" + +namespace Logger +{ + + class cFileListener + : public cLoggerListener + { + public: + + cFileListener(); + cFileListener(AString a_Filename); + + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override; + private: + cFile m_File; + }; + + cLoggerListener * MakeConsoleListener(); +} diff --git a/src/LogDispacher.cpp b/src/LogDispacher.cpp new file mode 100644 index 000000000..337d718e6 --- /dev/null +++ b/src/LogDispacher.cpp @@ -0,0 +1,115 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Log.h" +#include "OSSupport/IsThread.h" + + + +namespace Logger +{ + + cLogDispacher & GetInstance(void) + { + static cLogDispacher Instance; + return Instance; + } + + void InitiateMultithreading() + { + GetInstance(); + } + + void cLogDispacher::LogSimple(AString a_Message, eLogLevel a_LogLevel) + { + time_t rawtime; + time ( &rawtime); + + struct tm* timeinfo; + #ifdef _MSC_VER + struct tm timeinforeal; + timeinfo = &timeinforeal; + localtime_s(timeinfo, &rawtime); + #else + timeinfo = localtime( &rawtime); + #endif + + AString Line; + #ifdef _DEBUG + Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #else + Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #endif + + + cCSLock Lock(m_CriticalSection); + for(size_t i = 0; i < m_LogListeners.size(); i++) + { + m_LogListeners[i]->Log(a_Message, a_LogLevel); + } + } + + + + + + void cLogDispacher::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) + { + AString Message; + AppendVPrintf(Message, a_Format, a_ArgList); + LogSimple(Message, a_LogLevel); + } + + void cLogDispacher::AttachListener(Logger::cLoggerListener * a_Listener) + { + cCSLock Lock(m_CriticalSection); + m_LogListeners.push_back(a_Listener); + } + + void cLogDispacher::DetachListener(Logger::cLoggerListener * a_Listener) + { + cCSLock Lock(m_CriticalSection); + m_LogListeners.erase(std::remove(m_LogListeners.begin(), m_LogListeners.end(), a_Listener)); + } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +// Global functions + +void LOG(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log(a_Format, Logger::llRegular, argList); + va_end(argList); +} + +void LOGINFO(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llInfo, argList); + va_end(argList); +} + +void LOGWARN(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llWarning, argList); + va_end(argList); +} + +void LOGERROR(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llError, argList); + va_end(argList); +} + + + + diff --git a/src/LogDispacher.h b/src/LogDispacher.h new file mode 100644 index 000000000..31b3b3fc1 --- /dev/null +++ b/src/LogDispacher.h @@ -0,0 +1,85 @@ + +#pragma once + + + +class cLog; + + +namespace Logger +{ + + enum eLogLevel + { + llRegular, + llInfo, + llWarning, + llError, + }; + + class cLogDispacher; + + // Must be called before calling GetInstance in a multithreaded context + void InitiateMultithreading(); + + cLogDispacher & GetInstance(void); + + class cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) = 0; + + virtual ~cLoggerListener(){} + }; + + class cLogDispacher + { + public: + + void Log (const char * a_Format, Logger::eLogLevel a_LogLevel, va_list a_ArgList) FORMATSTRING(2, 0); + + /** Logs the simple text message at the specified log level. */ + void LogSimple(AString a_Message, Logger::eLogLevel a_LogLevel = Logger::llRegular); + + void AttachListener(Logger::cLoggerListener * a_Listener); + void DetachListener(Logger::cLoggerListener * a_Listener); + + private: + + cCriticalSection m_CriticalSection; + std::vector m_LogListeners; + + }; + +} + + + + + + +extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2); + + + + + +// In debug builds, translate LOGD to LOG, otherwise leave it out altogether: +#ifdef _DEBUG + #define LOGD LOG +#else + #define LOGD(...) +#endif // _DEBUG + + + + + +#define LOGWARNING LOGWARN + + + + From be780b380ee91f5de27eecb3d8809506d4198534 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 20:10:47 +0100 Subject: [PATCH 145/751] Fixed Tools to work with new logging framework --- Tools/MCADefrag/CMakeLists.txt | 6 +- Tools/MCADefrag/MCADefrag.cpp | 16 ++- Tools/ProtoProxy/CMakeLists.txt | 6 +- src/CMakeLists.txt | 2 - src/Log.cpp | 169 -------------------------------- src/Log.h | 30 ------ src/LogDispacher.cpp | 1 - src/LogDispacher.h | 4 - 8 files changed, 18 insertions(+), 216 deletions(-) delete mode 100644 src/Log.cpp delete mode 100644 src/Log.h diff --git a/Tools/MCADefrag/CMakeLists.txt b/Tools/MCADefrag/CMakeLists.txt index 2a021049f..e237b6429 100644 --- a/Tools/MCADefrag/CMakeLists.txt +++ b/Tools/MCADefrag/CMakeLists.txt @@ -39,14 +39,12 @@ set_exe_flags() set(SHARED_SRC ../../src/StringCompression.cpp ../../src/StringUtils.cpp - ../../src/Log.cpp - ../../src/MCLogger.cpp + ../../src/Listeners.cpp + ../../src/LogDispacher.cpp ) set(SHARED_HDR ../../src/ByteBuffer.h ../../src/StringUtils.h - ../../src/Log.h - ../../src/MCLogger.h ) flatten_files(SHARED_SRC) flatten_files(SHARED_HDR) diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index a2de7f957..702b04ebf 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -5,7 +5,8 @@ #include "Globals.h" #include "MCADefrag.h" -#include "MCLogger.h" +#include "LogDispacher.h" +#include "Listeners.h" #include "zlib/zlib.h" @@ -21,7 +22,13 @@ static const Byte g_Zeroes[4096] = {0}; int main(int argc, char ** argv) { - new cMCLogger(Printf("Defrag_%08x.log", time(NULL))); + Logger::cLoggerListener * consoleLogListener = Logger::MakeConsoleListener(); + Logger::cLoggerListener * fileLogListener = new Logger::cFileListener(); + Logger::GetInstance().AttachListener(consoleLogListener); + Logger::GetInstance().AttachListener(fileLogListener); + + Logger::InitiateMultithreading(); + cMCADefrag Defrag; if (!Defrag.Init(argc, argv)) { @@ -30,6 +37,11 @@ int main(int argc, char ** argv) Defrag.Run(); + Logger::GetInstance().DetachListener(consoleLogListener); + delete consoleLogListener; + Logger::GetInstance().DetachListener(fileLogListener); + delete fileLogListener; + return 0; } diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt index f0796363c..16c59bb43 100644 --- a/Tools/ProtoProxy/CMakeLists.txt +++ b/Tools/ProtoProxy/CMakeLists.txt @@ -34,20 +34,18 @@ set_exe_flags() set(SHARED_SRC ../../src/ByteBuffer.cpp ../../src/StringUtils.cpp - ../../src/Log.cpp - ../../src/MCLogger.cpp ../../src/PolarSSL++/AesCfb128Decryptor.cpp ../../src/PolarSSL++/AesCfb128Encryptor.cpp ../../src/PolarSSL++/CryptoKey.cpp ../../src/PolarSSL++/CtrDrbgContext.cpp ../../src/PolarSSL++/EntropyContext.cpp ../../src/PolarSSL++/RsaPrivateKey.cpp + ../../src/Listeners.cpp + ../../src/LogDispacher.cpp ) set(SHARED_HDR ../../src/ByteBuffer.h ../../src/StringUtils.h - ../../src/Log.h - ../../src/MCLogger.h ../../src/PolarSSL++/AesCfb128Decryptor.h ../../src/PolarSSL++/AesCfb128Encryptor.h ../../src/PolarSSL++/CryptoKey.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0feee4fcb..bca6a2eb0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,6 @@ SET (SRCS LineBlockTracer.cpp LinearInterpolation.cpp Listeners.cpp - Log.cpp LogDispacher.cpp Map.cpp MapManager.cpp @@ -109,7 +108,6 @@ SET (HDRS LineBlockTracer.h LinearInterpolation.h LinearUpscale.h - Log.h LogDispacher.h Map.h MapManager.h diff --git a/src/Log.cpp b/src/Log.cpp deleted file mode 100644 index 7686a0fb4..000000000 --- a/src/Log.cpp +++ /dev/null @@ -1,169 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Log.h" - -#include -#include -#include "OSSupport/IsThread.h" - -#if defined(ANDROID_NDK) - #include - #include "ToJava.h" -#endif - - - - -cLog* cLog::s_Log = NULL; - -cLog::cLog(const AString & a_FileName) - : m_File(NULL) -{ - s_Log = this; - - // create logs directory - cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); - - OpenLog((FILE_IO_PREFIX + AString("logs/") + a_FileName).c_str()); -} - - - - - -cLog::~cLog() -{ - CloseLog(); - s_Log = NULL; -} - - - - - -cLog * cLog::GetInstance() -{ - if (s_Log != NULL) - { - return s_Log; - } - - new cLog("log.txt"); - return s_Log; -} - - - - - -void cLog::CloseLog() -{ - if (m_File) - fclose (m_File); - m_File = 0; -} - - - - - -void cLog::OpenLog( const char* a_FileName) -{ - if (m_File) fclose (m_File); - #ifdef _MSC_VER - fopen_s( &m_File, a_FileName, "a+"); - #else - m_File = fopen(a_FileName, "a+"); - #endif -} - - - - - -void cLog::ClearLog() -{ - #ifdef _MSC_VER - if (fopen_s( &m_File, "log.txt", "w") == 0) - fclose (m_File); - #else - m_File = fopen("log.txt", "w"); - if (m_File) - fclose (m_File); - #endif - m_File = NULL; -} - - - - - -void cLog::Log(const char * a_Format, va_list argList) -{ - AString Message; - AppendVPrintf(Message, a_Format, argList); - - time_t rawtime; - time ( &rawtime); - - struct tm* timeinfo; -#ifdef _MSC_VER - struct tm timeinforeal; - timeinfo = &timeinforeal; - localtime_s(timeinfo, &rawtime); -#else - timeinfo = localtime( &rawtime); -#endif - - AString Line; - #ifdef _DEBUG - Printf(Line, "[%04lx|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str()); - #else - Printf(Line, "[%02d:%02d:%02d] %s", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str()); - #endif - if (m_File) - { - fprintf(m_File, "%s\n", Line.c_str()); - fflush(m_File); - } - - // Print to console: -#if defined(ANDROID_NDK) - // __android_log_vprint(ANDROID_LOG_ERROR, "MCServer", a_Format, argList); - __android_log_print(ANDROID_LOG_ERROR, "MCServer", "%s", Line.c_str()); - // CallJavaFunction_Void_String(g_JavaThread, "AddToLog", Line); -#else - printf("%s", Line.c_str()); -#endif - - #if defined (_WIN32) && defined(_DEBUG) - // In a Windows Debug build, output the log to debug console as well: - OutputDebugStringA((Line + "\n").c_str()); - #endif // _WIN32 -} - - - - - -void cLog::Log(const char * a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - Log(a_Format, argList); - va_end(argList); -} - - - - - -void cLog::SimpleLog(const char * a_String) -{ - Log("%s", a_String); -} - - - - diff --git a/src/Log.h b/src/Log.h deleted file mode 100644 index dc88aa92f..000000000 --- a/src/Log.h +++ /dev/null @@ -1,30 +0,0 @@ - -#pragma once - - - - - -class cLog -{ -private: - FILE * m_File; - static cLog * s_Log; - -public: - cLog(const AString & a_FileName); - ~cLog(); - void Log(const char * a_Format, va_list argList) FORMATSTRING(2, 0); - void Log(const char * a_Format, ...) FORMATSTRING(2, 3); - // tolua_begin - void SimpleLog(const char * a_String); - void OpenLog(const char * a_FileName); - void CloseLog(); - void ClearLog(); - static cLog* GetInstance(); -}; - - - - - diff --git a/src/LogDispacher.cpp b/src/LogDispacher.cpp index 337d718e6..abca6a898 100644 --- a/src/LogDispacher.cpp +++ b/src/LogDispacher.cpp @@ -1,7 +1,6 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Log.h" #include "OSSupport/IsThread.h" diff --git a/src/LogDispacher.h b/src/LogDispacher.h index 31b3b3fc1..1472b392a 100644 --- a/src/LogDispacher.h +++ b/src/LogDispacher.h @@ -2,10 +2,6 @@ #pragma once - -class cLog; - - namespace Logger { From 63a07b7ffc0d34beba6752c3c1f4f5771eb2c36b Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 20:47:16 +0100 Subject: [PATCH 146/751] Fixed potential crash in Player.cpp Fixes CID 71780 If ShouldBroadcastDeathMessages is false the pointer would fall through to a check agaist it being a player --- src/Entities/Player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 8fa060a5d..8667344c7 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -906,6 +906,10 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) } GetWorld()->BroadcastChatDeath(Printf("%s %s", GetName().c_str(), DamageText.c_str())); } + else if (a_TDI.Attacker == NULL) // && !m_World->ShouldBroadcastDeathMessages() by fallthrough + { + // no-op + } else if (a_TDI.Attacker->IsPlayer()) { cPlayer * Killer = (cPlayer *)a_TDI.Attacker; From 07103ed9d7af1c37623d6c8c96ec5084938c244b Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 21:26:28 +0100 Subject: [PATCH 147/751] Spaces --- src/Entities/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 8667344c7..608316e9a 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -906,7 +906,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) } GetWorld()->BroadcastChatDeath(Printf("%s %s", GetName().c_str(), DamageText.c_str())); } - else if (a_TDI.Attacker == NULL) // && !m_World->ShouldBroadcastDeathMessages() by fallthrough + else if (a_TDI.Attacker == NULL) // && !m_World->ShouldBroadcastDeathMessages() by fallthrough { // no-op } From d95768d01a93a14df38f6e0e33ca180b779c5df0 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Sun, 10 Aug 2014 22:36:02 +0200 Subject: [PATCH 148/751] Bunch of tweaks: Renamed Quarts to Quartz Using const_iterator instead of iterator Used CheckBasicStyle script to find style errors --- src/Generating/ComposableGenerator.cpp | 14 +++++++------- src/Generating/StructGen.cpp | 2 +- src/Generating/StructGen.h | 14 +++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 58ad8fc2e..2f575fe27 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -424,13 +424,13 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { cStructGenOreNests::OreList Ores; - // Quarts vein - cStructGenOreNests::OreInfo QuartsVein; - QuartsVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE; - QuartsVein.MaxHeight = 255; - QuartsVein.NumNests = 80; - QuartsVein.NestSize = 8; - Ores.push_back(QuartsVein); + // Quartz vein + cStructGenOreNests::OreInfo QuartzVein; + QuartzVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE; + QuartzVein.MaxHeight = 255; + QuartzVein.NumNests = 80; + QuartzVein.NestSize = 8; + Ores.push_back(QuartzVein); m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK)); diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index 1a43f2b2e..731324b0d 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -276,7 +276,7 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) int seq = 1; // Generate the ores from the ore list. - for (OreList::iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr) + for (OreList::const_iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr) { GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, seq); seq++; diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h index e2fe8bc1a..55d5bc1c7 100644 --- a/src/Generating/StructGen.h +++ b/src/Generating/StructGen.h @@ -78,16 +78,16 @@ class cStructGenOreNests : public: struct OreInfo { - BLOCKTYPE BlockType; // The type of the nest. - int MaxHeight; // The highest possible a nest can occur - int NumNests; // How many nests per chunk - int NestSize; // The amount of blocks a nest can have. + BLOCKTYPE BlockType; // The type of the nest. + int MaxHeight; // The highest possible a nest can occur + int NumNests; // How many nests per chunk + int NestSize; // The amount of blocks a nest can have. }; typedef std::vector OreList; - cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) : - m_Noise(a_Seed), + cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) : + m_Noise(a_Seed), m_Seed(a_Seed), m_OreList(a_OreList), m_ToReplace(a_ToReplace) @@ -97,7 +97,7 @@ protected: cNoise m_Noise; int m_Seed; - OreList m_OreList; // A list of possible ores. + OreList m_OreList; // A list of possible ores. BLOCKTYPE m_ToReplace; // cFinishGen override: From 5623a045f598a068a7bae77cc3acad62f6160452 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 22:06:56 +0100 Subject: [PATCH 149/751] Fixed potential null dereference Fixes CID 70466 --- src/BlockEntities/HopperEntity.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index 48d3b8dcc..88e7b8e1b 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -549,13 +549,13 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ) { // Try the chest directly connected to the hopper: - cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); - if (Chest == NULL) + cChestEntity * ConnectedChest = (cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); + if (ConnectedChest == NULL) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, a_BlockX, a_BlockY, a_BlockZ); return false; } - if (MoveItemsToGrid(*Chest)) + if (MoveItemsToGrid(*ConnectedChest)) { // Chest block directly connected was not full return true; @@ -586,13 +586,13 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block } BLOCKTYPE Block = Neighbor->GetBlock(x, a_BlockY, z); - if (Block != Chest->GetBlockType()) + if (Block != ConnectedChest->GetBlockType()) { // Not the same kind of chest continue; } - Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z); + cChestEntity * Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z); if (Chest == NULL) { LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d} (%d, %d)", __FUNCTION__, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z, x, z); From df96f437a3802ffeb36c1fefca3d2674bbb94079 Mon Sep 17 00:00:00 2001 From: Tycho Date: Sun, 10 Aug 2014 22:15:52 +0100 Subject: [PATCH 150/751] Fixed circular dependecy luaState_Call.inc --- src/Bindings/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index a2b381a26..54152668a 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -45,7 +45,6 @@ set(BINDING_DEPENDENCIES ../Bindings/AllToLua.pkg ../Bindings/gen_LuaState_Call.lua ../Bindings/LuaFunctions.h - ../Bindings/LuaState_Call.inc ../Bindings/LuaWindow.h ../Bindings/Plugin.h ../Bindings/PluginLua.h @@ -128,6 +127,7 @@ if (NOT MSVC) endif () set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES GENERATED TRUE) set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.h PROPERTIES GENERATED TRUE) +set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/LuaState_Call.inc PROPERTIES GENERATED TRUE) if(NOT MSVC) add_library(Bindings ${SRCS} ${HDRS}) From dba672361164dc5dc5f94d24bde3176c7de89d4c Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 2 Aug 2014 22:42:53 -0700 Subject: [PATCH 151/751] Player.cpp: change unnamed enum to constant integers --- src/Entities/Player.cpp | 2 +- src/Entities/Player.h | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 608316e9a..91bcddca3 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -509,7 +509,7 @@ void cPlayer::Heal(int a_Health) void cPlayer::SetFoodLevel(int a_FoodLevel) { - int FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL)); + int FoodLevel = Clamp(a_FoodLevel, 0, MAX_FOOD_LEVEL); if (cRoot::Get()->GetPluginManager()->CallHookPlayerFoodLevelChange(*this, FoodLevel)) { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index e26808bfc..f345a0207 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -29,12 +29,13 @@ class cPlayer : typedef cPawn super; public: - enum - { - MAX_HEALTH = 20, - MAX_FOOD_LEVEL = 20, - EATING_TICKS = 30, ///< Number of ticks it takes to eat an item - } ; + static const int MAX_HEALTH = 20; + + static const int MAX_FOOD_LEVEL = 20; + + /** Number of ticks it takes to eat an item */ + static const int EATING_TICKS = 30; + // tolua_end CLASS_PROTODEF(cPlayer) From 92f67789fc24572092a70d582aef22d7ef1dd272 Mon Sep 17 00:00:00 2001 From: archshift Date: Sat, 2 Aug 2014 22:56:08 -0700 Subject: [PATCH 152/751] Gave names to unnamed enums --- src/Enchantments.h | 2 +- src/HTTPServer/HTTPMessage.h | 2 +- src/Inventory.h | 4 ++-- src/Protocol/Protocol125.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Enchantments.h b/src/Enchantments.h index 98d7c0d36..824f6aa55 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -43,7 +43,7 @@ public: /** Individual enchantment IDs, corresponding to their NBT IDs: http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs */ - enum + enum eEnchantment { enchProtection = 0, enchFireProtection = 1, diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h index e402c8ad6..c0667030f 100644 --- a/src/HTTPServer/HTTPMessage.h +++ b/src/HTTPServer/HTTPMessage.h @@ -18,7 +18,7 @@ class cHTTPMessage { public: - enum + enum eStatus { HTTP_OK = 200, HTTP_BAD_REQUEST = 400, diff --git a/src/Inventory.h b/src/Inventory.h index ed134aee4..5628fb0da 100644 --- a/src/Inventory.h +++ b/src/Inventory.h @@ -39,8 +39,8 @@ public: enum { invArmorCount = 4, - invInventoryCount = 9 * 3, - invHotbarCount = 9, + invInventoryCount = 9 * 3, + invHotbarCount = 9, invArmorOffset = 0, invInventoryOffset = invArmorOffset + invArmorCount, diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 18efeb079..3adac3055 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -103,7 +103,7 @@ public: protected: /// Results of packet-parsing: - enum + enum eParseResult { PARSE_OK = 1, PARSE_ERROR = -1, From 47c928cab7d1ff73e50925bc7ef50586b6ec9821 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 11 Aug 2014 00:20:28 +0200 Subject: [PATCH 153/751] Exported daylight cycle flag to the protocol. --- src/ClientHandle.cpp | 12 +++--------- src/ClientHandle.h | 2 +- src/Protocol/Protocol.h | 2 +- src/Protocol/Protocol125.cpp | 5 ++++- src/Protocol/Protocol125.h | 2 +- src/Protocol/Protocol14x.cpp | 8 +++++++- src/Protocol/Protocol14x.h | 2 +- src/Protocol/Protocol17x.cpp | 7 ++++++- src/Protocol/Protocol17x.h | 2 +- src/Protocol/ProtocolRecognizer.cpp | 4 ++-- src/Protocol/ProtocolRecognizer.h | 2 +- src/World.cpp | 9 +-------- 12 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 37d7edbc1..d386f3576 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -342,13 +342,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, } // Send time: - Int64 TimeOfDay = World->GetTimeOfDay(); - if (!World->IsDaylightCycleEnabled()) - { - // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. - TimeOfDay = std::min(-TimeOfDay, -1); - } - m_Protocol->SendTimeUpdate(World->GetWorldAge(), TimeOfDay); + m_Protocol->SendTimeUpdate(World->GetWorldAge(), World->GetTimeOfDay(), World->IsDaylightCycleEnabled()); // Send contents of the inventory window m_Protocol->SendWholeInventory(*m_Player->GetWindow()); @@ -2595,9 +2589,9 @@ void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) -void cClientHandle::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +void cClientHandle::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { - m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay); + m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay, a_DoDaylightCycle); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 1bf397ad2..7ae70a07f 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -179,7 +179,7 @@ public: void SendTabCompletionResults(const AStringVector & a_Results); void SendTeleportEntity (const cEntity & a_Entity); void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); - void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay); // tolua_export + void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle); // tolua_export void SendUnloadChunk (int a_ChunkX, int a_ChunkZ); void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index d110f2af9..8e1842ec1 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -116,7 +116,7 @@ public: virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0; virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) = 0; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 538d31642..a66c64309 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -1072,8 +1072,11 @@ void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) -void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { + // This protocol doesn't support a_DoDaylightCycle on false. + UNUSED(a_DoDaylightCycle); + cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_TIME); // Use a_WorldAge for daycount, and a_TimeOfDay for the proper time of day: diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 18efeb079..0973bb005 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -88,7 +88,7 @@ public: virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {} virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index 8b177ea48..3b6b6a42a 100644 --- a/src/Protocol/Protocol14x.cpp +++ b/src/Protocol/Protocol14x.cpp @@ -130,8 +130,14 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src -void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { + if (!a_DoDaylightCycle) + { + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + a_TimeOfDay = std::min(-a_TimeOfDay, -1LL); + } + cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_TIME); WriteInt64(a_WorldAge); diff --git a/src/Protocol/Protocol14x.h b/src/Protocol/Protocol14x.h index ca497bbc1..227cc8cc7 100644 --- a/src/Protocol/Protocol14x.h +++ b/src/Protocol/Protocol14x.h @@ -34,7 +34,7 @@ public: // Sending commands (alphabetically sorted): virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; // Specific packet parsers: virtual int ParseLocaleViewDistance(void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 318342f09..a724133fc 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1286,9 +1286,14 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) -void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { ASSERT(m_State == 3); // In game mode? + if (!a_DoDaylightCycle) + { + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + a_TimeOfDay = std::min(-a_TimeOfDay, -1LL); + } cPacketizer Pkt(*this, 0x03); Pkt.WriteInt64(a_WorldAge); diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 9c9f563e0..ccfa19eb6 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -120,7 +120,7 @@ public: virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index a7fb7bcc2..18694572a 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -716,10 +716,10 @@ void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_Bloc -void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) { ASSERT(m_Protocol != NULL); - m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay); + m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay, a_DoDaylightCycle); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 65829ef73..28572a8fd 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -123,7 +123,7 @@ public: virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; diff --git a/src/World.cpp b/src/World.cpp index dcca0519e..5298f3b03 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2250,13 +2250,6 @@ void cWorld::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { - int TimeOfDay = m_TimeOfDay; - if (!m_IsDaylightCycleEnabled) - { - // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. - TimeOfDay = std::min(-TimeOfDay, -1); - } - cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { @@ -2265,7 +2258,7 @@ void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude) { continue; } - ch->SendTimeUpdate(m_WorldAge, TimeOfDay); + ch->SendTimeUpdate(m_WorldAge, m_TimeOfDay, m_IsDaylightCycleEnabled); } } From a7eb4032ee32f8299857ccdfc4ad9f45227abb05 Mon Sep 17 00:00:00 2001 From: archshift Date: Sun, 10 Aug 2014 17:13:14 -0700 Subject: [PATCH 154/751] Fixed tolua error with static initialization --- src/Entities/Player.cpp | 9 +++++++++ src/Entities/Player.h | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 91bcddca3..4398a5bf3 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -33,6 +33,15 @@ +const int cPlayer::MAX_HEALTH = 20; + +const int cPlayer::MAX_FOOD_LEVEL = 20; + +/** Number of ticks it takes to eat an item */ +const int cPlayer::EATING_TICKS = 30; + + + cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f345a0207..d3ed1ef9d 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -29,12 +29,12 @@ class cPlayer : typedef cPawn super; public: - static const int MAX_HEALTH = 20; + static const int MAX_HEALTH; - static const int MAX_FOOD_LEVEL = 20; + static const int MAX_FOOD_LEVEL; /** Number of ticks it takes to eat an item */ - static const int EATING_TICKS = 30; + static const int EATING_TICKS; // tolua_end From 202a0d1c1d6de6cc1b229026d0304a736a1d9b75 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 11 Aug 2014 14:24:36 +0200 Subject: [PATCH 155/751] Fixed cancelled fire interact from all directions. --- src/ClientHandle.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 3e046f38d..8eff45cf4 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -920,9 +920,13 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB ) { m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))->IsClickedThrough()) + if (a_BlockFace != BLOCK_FACE_NONE) { - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ))->IsClickedThrough()) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + } } return; } @@ -932,9 +936,13 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB { // A plugin doesn't agree with the action, replace the block on the client and quit: m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))->IsClickedThrough()) + if (a_BlockFace != BLOCK_FACE_NONE) { - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ))->IsClickedThrough()) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + } } return; } From 0a52ed6eb97ca5cc08fe255bfd04f78b4ea19a7e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 11 Aug 2014 15:33:20 +0200 Subject: [PATCH 156/751] cProtocol172: Check return values. Fixes CID 43489, CID 43490, CID 43491, CID 43493, CID 66410, CID 66411, CID 66416, CID 66417, CID 66418, CID 66419, CID 66420, CID 66421, CID 66422, CID 66423, CID 66424, CID 66425, CID 66429, CID 66430, CID 66431 --- src/Protocol/Protocol17x.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 318342f09..1f8ca00bb 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -48,7 +48,10 @@ Implements the 1.7.x protocol classes: #define HANDLE_READ(ByteBuf, Proc, Type, Var) \ Type Var; \ - ByteBuf.Proc(Var); + if (!ByteBuf.Proc(Var))\ + {\ + return;\ + } @@ -1700,8 +1703,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) { - Int64 Timestamp; - a_ByteBuffer.ReadBEInt64(Timestamp); + HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp); cPacketizer Pkt(*this, 0x01); // Ping packet Pkt.WriteInt64(Timestamp); @@ -2054,7 +2056,10 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length); AString Data; - a_ByteBuffer.ReadString(Data, Length); + if (!a_ByteBuffer.ReadString(Data, Length)) + { + return; + } m_Client->HandlePluginMessage(Channel, Data); } From e0b45c189328d668f5177e529abe99387fc49cf3 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 11 Aug 2014 16:06:40 +0200 Subject: [PATCH 157/751] 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 f7726317c9c1c27fa3d0b9b7c2df35ffff6f1f1a Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Mon, 11 Aug 2014 18:57:41 +0200 Subject: [PATCH 158/751] Add entry for bat in monsters.ini --- MCServer/monsters.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini index d29b01d8f..c4bc8c810 100644 --- a/MCServer/monsters.ini +++ b/MCServer/monsters.ini @@ -185,4 +185,10 @@ AttackDamage=6.0 SightDistance=25.0 MaxHealth=100 +[Bat] +AttackRange=2.0 +AttackRate=1 +AttackDamage=0.0 +SightDistance=25.0 +MaxHealth=6 From 74fabb079c710ab9f81e0b7ee30a8a3e3604595c Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 11 Aug 2014 22:34:33 +0200 Subject: [PATCH 159/751] Moved the clicked-through block check to the top of the function. --- src/Blocks/BlockFire.h | 5 ---- src/ClientHandle.cpp | 53 ++++++++++++++---------------------------- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index f52825362..df50d5962 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -40,11 +40,6 @@ public: FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface); } - virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - a_ChunkInterface.DigBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - } - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // No pickups from this block diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8eff45cf4..f09e9531d 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -912,6 +912,23 @@ 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) + { + int BlockX = a_BlockX; + int BlockY = a_BlockY; + int BlockZ = a_BlockZ; + AddFaceDirection(BlockX, BlockY, BlockZ, a_BlockFace); + if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(BlockX, BlockY, BlockZ))->IsClickedThrough()) + { + a_BlockX = BlockX; + 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) || @@ -920,14 +937,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB ) { m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - if (a_BlockFace != BLOCK_FACE_NONE) - { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ))->IsClickedThrough()) - { - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - } - } return; } @@ -936,14 +945,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB { // A plugin doesn't agree with the action, replace the block on the client and quit: m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - if (a_BlockFace != BLOCK_FACE_NONE) - { - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - if (cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ))->IsClickedThrough()) - { - m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - } - } return; } @@ -1067,26 +1068,6 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc m_LastDigBlockY = a_BlockY; m_LastDigBlockZ = a_BlockZ; - // 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) - { - int pX = a_BlockX; - int pY = a_BlockY; - int pZ = a_BlockZ; - - AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false) - cBlockHandler * Handler = cBlockInfo::GetHandler(m_Player->GetWorld()->GetBlock(pX, pY, pZ)); - - if (Handler->IsClickedThrough()) - { - cChunkInterface ChunkInterface(m_Player->GetWorld()->GetChunkMap()); - Handler->OnDigging(ChunkInterface, *m_Player->GetWorld(), m_Player, pX, pY, pZ); - return; - } - } - if ( (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately cBlockInfo::IsOneHitDig(a_OldBlock) // One-hit blocks get destroyed immediately, too From 01001d2a49a3366e9b1eccf938d5073ab9a2f06e Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 11 Aug 2014 22:37:28 +0200 Subject: [PATCH 160/751] Removes the fire if the block under the fire was broken. --- src/ClientHandle.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f09e9531d..4b5c52c8c 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1143,6 +1143,11 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo World->BroadcastSoundParticleEffect(2001, a_BlockX, a_BlockY, a_BlockZ, a_OldBlock, this); World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); + if (World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ) == E_BLOCK_FIRE) + { + World->SetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); + } + cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); } From cb980145820b1bb016dac17a28731cc0b600442a Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 11 Aug 2014 23:12:32 +0200 Subject: [PATCH 161/751] Revert "Removes the fire if the block under the fire was broken." This reverts commit 01001d2a49a3366e9b1eccf938d5073ab9a2f06e. --- src/ClientHandle.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 4b5c52c8c..f09e9531d 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1143,11 +1143,6 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo World->BroadcastSoundParticleEffect(2001, a_BlockX, a_BlockY, a_BlockZ, a_OldBlock, this); World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); - if (World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ) == E_BLOCK_FIRE) - { - World->SetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); - } - cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); } From 98443682671d0c39b19f86098f7bc900b7529b72 Mon Sep 17 00:00:00 2001 From: Tycho Date: Tue, 12 Aug 2014 16:05:04 +0100 Subject: [PATCH 162/751] Renamed Loggers --- Tools/MCADefrag/CMakeLists.txt | 4 +- Tools/MCADefrag/MCADefrag.cpp | 18 +-- Tools/ProtoProxy/CMakeLists.txt | 4 +- src/Bindings/ManualBindings.cpp | 10 +- src/CMakeLists.txt | 7 +- src/CompositeChat.cpp | 24 ++-- src/CompositeChat.h | 2 +- src/Globals.h | 2 +- src/Listeners.cpp | 236 ------------------------------- src/Listeners.h | 21 --- src/LogDispacher.cpp | 114 --------------- src/Logger.cpp | 109 ++++++++++++++ src/{LogDispacher.h => Logger.h} | 42 +++--- src/LoggerListeners.cpp | 231 ++++++++++++++++++++++++++++++ src/LoggerListeners.h | 17 +++ src/Root.cpp | 14 +- src/main.cpp | 2 +- 17 files changed, 418 insertions(+), 439 deletions(-) delete mode 100644 src/Listeners.cpp delete mode 100644 src/Listeners.h delete mode 100644 src/LogDispacher.cpp create mode 100644 src/Logger.cpp rename src/{LogDispacher.h => Logger.h} (51%) create mode 100644 src/LoggerListeners.cpp create mode 100644 src/LoggerListeners.h diff --git a/Tools/MCADefrag/CMakeLists.txt b/Tools/MCADefrag/CMakeLists.txt index e237b6429..42b42018b 100644 --- a/Tools/MCADefrag/CMakeLists.txt +++ b/Tools/MCADefrag/CMakeLists.txt @@ -39,8 +39,8 @@ set_exe_flags() set(SHARED_SRC ../../src/StringCompression.cpp ../../src/StringUtils.cpp - ../../src/Listeners.cpp - ../../src/LogDispacher.cpp + ../../src/LoggerListeners.cpp + ../../src/Logger.cpp ) set(SHARED_HDR ../../src/ByteBuffer.h diff --git a/Tools/MCADefrag/MCADefrag.cpp b/Tools/MCADefrag/MCADefrag.cpp index 702b04ebf..d5d233fd2 100644 --- a/Tools/MCADefrag/MCADefrag.cpp +++ b/Tools/MCADefrag/MCADefrag.cpp @@ -5,8 +5,8 @@ #include "Globals.h" #include "MCADefrag.h" -#include "LogDispacher.h" -#include "Listeners.h" +#include "Logger.h" +#include "LoggerListeners.h" #include "zlib/zlib.h" @@ -22,12 +22,12 @@ static const Byte g_Zeroes[4096] = {0}; int main(int argc, char ** argv) { - Logger::cLoggerListener * consoleLogListener = Logger::MakeConsoleListener(); - Logger::cLoggerListener * fileLogListener = new Logger::cFileListener(); - Logger::GetInstance().AttachListener(consoleLogListener); - Logger::GetInstance().AttachListener(fileLogListener); + cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * fileLogListener = new cFileListener(); + cLogger::GetInstance().AttachListener(consoleLogListener); + cLogger::GetInstance().AttachListener(fileLogListener); - Logger::InitiateMultithreading(); + cLogger::InitiateMultithreading(); cMCADefrag Defrag; if (!Defrag.Init(argc, argv)) @@ -37,9 +37,9 @@ int main(int argc, char ** argv) Defrag.Run(); - Logger::GetInstance().DetachListener(consoleLogListener); + cLogger::GetInstance().DetachListener(consoleLogListener); delete consoleLogListener; - Logger::GetInstance().DetachListener(fileLogListener); + cLogger::GetInstance().DetachListener(fileLogListener); delete fileLogListener; return 0; diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt index 16c59bb43..bc3923d90 100644 --- a/Tools/ProtoProxy/CMakeLists.txt +++ b/Tools/ProtoProxy/CMakeLists.txt @@ -40,8 +40,8 @@ set(SHARED_SRC ../../src/PolarSSL++/CtrDrbgContext.cpp ../../src/PolarSSL++/EntropyContext.cpp ../../src/PolarSSL++/RsaPrivateKey.cpp - ../../src/Listeners.cpp - ../../src/LogDispacher.cpp + ../../src/LoggerListeners.cpp + ../../src/Logger.cpp ) set(SHARED_HDR ../../src/ByteBuffer.h diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index d792cd0ee..e1e6585f0 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -168,7 +168,7 @@ static AString GetLogMessage(lua_State * tolua_S) static int tolua_LOG(lua_State * tolua_S) { // If the param is a cCompositeChat, read the log level from it: - Logger::eLogLevel LogLevel = Logger::llRegular; + cLogger::eLogLevel LogLevel = cLogger::llRegular; tolua_Error err; if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) { @@ -176,7 +176,7 @@ static int tolua_LOG(lua_State * tolua_S) } // Log the message: - Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); return 0; } @@ -186,7 +186,7 @@ static int tolua_LOG(lua_State * tolua_S) static int tolua_LOGINFO(lua_State * tolua_S) { - Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llInfo); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llInfo); return 0; } @@ -196,7 +196,7 @@ static int tolua_LOGINFO(lua_State * tolua_S) static int tolua_LOGWARN(lua_State * tolua_S) { - Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llWarning); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llWarning); return 0; } @@ -206,7 +206,7 @@ static int tolua_LOGWARN(lua_State * tolua_S) static int tolua_LOGERROR(lua_State * tolua_S) { - Logger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), Logger::llError); + cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llError); return 0; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bca6a2eb0..8925c9be8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,8 +42,8 @@ SET (SRCS LightingThread.cpp LineBlockTracer.cpp LinearInterpolation.cpp - Listeners.cpp - LogDispacher.cpp + LoggerListeners.cpp + Logger.cpp Map.cpp MapManager.cpp MobCensus.cpp @@ -108,7 +108,8 @@ SET (HDRS LineBlockTracer.h LinearInterpolation.h LinearUpscale.h - LogDispacher.h + Logger.h + LoggerListeners.h Map.h MapManager.h Matrix4.h diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index b702447be..0d339021e 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -353,23 +353,23 @@ AString cCompositeChat::ExtractText(void) const -Logger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) +cLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) { switch (a_MessageType) { - case mtCustom: return Logger::llRegular; - case mtFailure: return Logger::llWarning; - case mtInformation: return Logger::llInfo; - case mtSuccess: return Logger::llRegular; - case mtWarning: return Logger::llWarning; - case mtFatal: return Logger::llError; - case mtDeath: return Logger::llRegular; - case mtPrivateMessage: return Logger::llRegular; - case mtJoin: return Logger::llRegular; - case mtLeave: return Logger::llRegular; + case mtCustom: return cLogger::llRegular; + case mtFailure: return cLogger::llWarning; + case mtInformation: return cLogger::llInfo; + case mtSuccess: return cLogger::llRegular; + case mtWarning: return cLogger::llWarning; + case mtFatal: return cLogger::llError; + case mtDeath: return cLogger::llRegular; + case mtPrivateMessage: return cLogger::llRegular; + case mtJoin: return cLogger::llRegular; + case mtLeave: return cLogger::llRegular; } ASSERT(!"Unhandled MessageType"); - return Logger::llError; + return cLogger::llError; } diff --git a/src/CompositeChat.h b/src/CompositeChat.h index cc7c446c3..2dc21b98f 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -196,7 +196,7 @@ public: /** Converts the MessageType to a LogLevel value. Used by the logging bindings when logging a cCompositeChat object. */ - static Logger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); + static cLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); protected: /** All the parts that */ diff --git a/src/Globals.h b/src/Globals.h index ae7a68e7f..de1024010 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -249,7 +249,7 @@ template class SizeChecker; #include "OSSupport/Event.h" #include "OSSupport/Thread.h" #include "OSSupport/File.h" - #include "LogDispacher.h" + #include "Logger.h" #else // Logging functions void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2); diff --git a/src/Listeners.cpp b/src/Listeners.cpp deleted file mode 100644 index 384dcaf91..000000000 --- a/src/Listeners.cpp +++ /dev/null @@ -1,236 +0,0 @@ - -#include "Globals.h" - -#include "Listeners.h" - -#if defined(_WIN32) - #include // Needed for _isatty(), not available on Linux -#elif defined(__linux) && !defined(ANDROID_NDK) - #include // Needed for isatty() on Linux -#elif defined(ANDROID_NDK) - #include -#endif - - -namespace Logger -{ - - #if defined(_WIN32) || (defined (__linux) && !defined(ANDROID_NDK)) - class cColouredConsoleListener - : public cLoggerListener - { - - virtual void SetLogColour(eLogLevel a_LogLevel) = 0; - virtual void SetDefaultLogColour() = 0; - - virtual void Log(AString a_Message, eLogLevel a_LogLevel) override - { - SetLogColour(a_LogLevel); - puts(a_Message.c_str()); - SetDefaultLogColour(); - } - }; - #endif - - #ifdef _WIN32 - class cWindowsConsoleListener - : public cColouredConsoleListener - { - public: - cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) : - m_Console(a_Console), - m_DefaultConsoleAttrib(a_DefaultConsoleAttrib) - { - } - - #ifdef DEBUG - virtual void Log(AString a_Message, eLogLevel a_LogLevel) override - { - cColouredConsoleListener::Log(a_Message, a_LogLevel); - // In a Windows Debug build, output the log to debug console as well: - OutputDebugStringA(a_Message.c_str()); - } - #endif // _WIN32 - - - virtual void SetLogColour(eLogLevel a_LogLevel) override - { - // by default, gray on black - WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - switch (a_LogLevel) - { - case llRegular: - // Gray on black - Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - break; - case llInfo: - // Yellow on black - Attrib = FOREGROUND_GREEN | ; - break; - case llWarning: - // Red on black - Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; - break; - case llError: - // Black on red - Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; - break; - } - SetConsoleTextAttribute(m_Console, Attrib); - } - virtual void SetDefaultLogColour() override - { - SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); - } - private: - HANDLE m_Console; - WORD m_DefaultConsoleAttrib; - }; - #elif defined (__linux) && !defined(ANDROID_NDK) - class cLinuxConsoleListener - : public cColouredConsoleListener - { - public: - virtual void SetLogColour(eLogLevel a_LogLevel) override - { - switch (a_LogLevel) - { - case llRegular: - // Whatever the console default is - printf("\x1b[0m"); - break; - case llInfo: - // Yellow on black - printf("\x1b[33;1m"); - break; - case llWarning: - // Red on black - printf("\x1b[31;1m"); - break; - case llError: - // Yellow on red - printf("\x1b[1;33;41;1m"); - break; - } - } - virtual void SetDefaultLogColour() override - { - // Whatever the console default is - printf("\x1b[0m"); - } - }; - #elif defined(ANDROID_NDK) - class cAndroidConsoleListener - : public cLoggerListener - { - public: - virtual void Log(AString a_Message, eLogLevel a_LogLevel) override - { - android_LogPriority AndroidLogLevel; - switch (a_LogLevel) - { - case llRegular: - AndroidLogLevel = ANDROID_LOG_VERBOSE; - break; - case llInfo: - AndroidLogLevel = ANDROID_LOG_INFO; - break; - case llWarning: - AndroidLogLevel = ANDROID_LOG_WARNING; - break; - case llError: - AndroidLogLevel = ANDROID_LOG_ERROR; - break; - } - __android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str()); - } - }; - #endif - - class cVanillaCPPConsoleListener - : public cLoggerListener - { - public: - virtual void Log(AString a_Message, eLogLevel a_LogLevel) override - { - AString LogLevelString; - switch (a_LogLevel) - { - case llRegular: - LogLevelString = "Log"; - break; - case llInfo: - LogLevelString = "Info"; - break; - case llWarning: - LogLevelString = "Warning"; - break; - case llError: - LogLevelString = "Error"; - break; - } - printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); - } - }; - - - - cLoggerListener * MakeConsoleListener() - { - #ifdef _WIN32 - // See whether we are writing to a console the default console attrib: - bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); - if (ShouldColorOutput) - { - CONSOLE_SCREEN_BUFFER_INFO sbi; - HANDLE Console = getStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(Console, &sbi); - WORD DefaultConsoleAttrib = sbi.wAttributes; - return new cWindowsConsoleListener(Console, DefaultConsoleAttrib); - } else { - return new cVanillaCPPConsoleListener(); - } - - #elif defined (__linux) && !defined(ANDROID_NDK) - // TODO: lookup terminal in terminfo - if (isatty(fileno(stdout))) - { - return new cLinuxConsoleListener(); - } else { - return new cVanillaCPPConsoleListener(); - } - #else - return new cVanillaCPPConsoleListener(); - #endif - } - - cFileListener::cFileListener() - { - cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); - AString FileName; - FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL)); - m_File.Open(FileName, cFile::fmAppend); - } - - void cFileListener::Log(AString a_Message, eLogLevel a_LogLevel) - { - AString LogLevelString; - switch (a_LogLevel) - { - case llRegular: - LogLevelString = "Log"; - break; - case llInfo: - LogLevelString = "Info"; - break; - case llWarning: - LogLevelString = "Warning"; - break; - case llError: - LogLevelString = "Error"; - break; - } - m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); - } - -} diff --git a/src/Listeners.h b/src/Listeners.h deleted file mode 100644 index bc29d0c06..000000000 --- a/src/Listeners.h +++ /dev/null @@ -1,21 +0,0 @@ - -#include "LogDispacher.h" - -namespace Logger -{ - - class cFileListener - : public cLoggerListener - { - public: - - cFileListener(); - cFileListener(AString a_Filename); - - virtual void Log(AString a_Message, eLogLevel a_LogLevel) override; - private: - cFile m_File; - }; - - cLoggerListener * MakeConsoleListener(); -} diff --git a/src/LogDispacher.cpp b/src/LogDispacher.cpp deleted file mode 100644 index abca6a898..000000000 --- a/src/LogDispacher.cpp +++ /dev/null @@ -1,114 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "OSSupport/IsThread.h" - - - -namespace Logger -{ - - cLogDispacher & GetInstance(void) - { - static cLogDispacher Instance; - return Instance; - } - - void InitiateMultithreading() - { - GetInstance(); - } - - void cLogDispacher::LogSimple(AString a_Message, eLogLevel a_LogLevel) - { - time_t rawtime; - time ( &rawtime); - - struct tm* timeinfo; - #ifdef _MSC_VER - struct tm timeinforeal; - timeinfo = &timeinforeal; - localtime_s(timeinfo, &rawtime); - #else - timeinfo = localtime( &rawtime); - #endif - - AString Line; - #ifdef _DEBUG - Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); - #else - Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); - #endif - - - cCSLock Lock(m_CriticalSection); - for(size_t i = 0; i < m_LogListeners.size(); i++) - { - m_LogListeners[i]->Log(a_Message, a_LogLevel); - } - } - - - - - - void cLogDispacher::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) - { - AString Message; - AppendVPrintf(Message, a_Format, a_ArgList); - LogSimple(Message, a_LogLevel); - } - - void cLogDispacher::AttachListener(Logger::cLoggerListener * a_Listener) - { - cCSLock Lock(m_CriticalSection); - m_LogListeners.push_back(a_Listener); - } - - void cLogDispacher::DetachListener(Logger::cLoggerListener * a_Listener) - { - cCSLock Lock(m_CriticalSection); - m_LogListeners.erase(std::remove(m_LogListeners.begin(), m_LogListeners.end(), a_Listener)); - } -}; - - - -//////////////////////////////////////////////////////////////////////////////// -// Global functions - -void LOG(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - Logger::GetInstance().Log(a_Format, Logger::llRegular, argList); - va_end(argList); -} - -void LOGINFO(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - Logger::GetInstance().Log( a_Format, Logger::llInfo, argList); - va_end(argList); -} - -void LOGWARN(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - Logger::GetInstance().Log( a_Format, Logger::llWarning, argList); - va_end(argList); -} - -void LOGERROR(const char* a_Format, ...) -{ - va_list argList; - va_start(argList, a_Format); - Logger::GetInstance().Log( a_Format, Logger::llError, argList); - va_end(argList); -} - - - - diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 000000000..e0ea973f8 --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,109 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "OSSupport/IsThread.h" + + +cLogger & cLogger::GetInstance(void) +{ + static cLogger Instance; + return Instance; +} + +void cLogger::InitiateMultithreading() +{ + GetInstance(); +} + +void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel) +{ + time_t rawtime; + time ( &rawtime); + + struct tm* timeinfo; + #ifdef _MSC_VER + struct tm timeinforeal; + timeinfo = &timeinforeal; + localtime_s(timeinfo, &rawtime); + #else + timeinfo = localtime( &rawtime); + #endif + + AString Line; + #ifdef _DEBUG + Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #else + Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #endif + + + cCSLock Lock(m_CriticalSection); + for(size_t i = 0; i < m_LogListeners.size(); i++) + { + m_LogListeners[i]->Log(a_Message, a_LogLevel); + } +} + + + + + +void cLogger::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) +{ + AString Message; + AppendVPrintf(Message, a_Format, a_ArgList); + LogSimple(Message, a_LogLevel); +} + +void cLogger::AttachListener(cListener * a_Listener) +{ + cCSLock Lock(m_CriticalSection); + m_LogListeners.push_back(a_Listener); +} + +void cLogger::DetachListener(cListener * a_Listener) +{ + cCSLock Lock(m_CriticalSection); + m_LogListeners.erase(std::remove(m_LogListeners.begin(), m_LogListeners.end(), a_Listener)); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// Global functions + +void LOG(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + cLogger::GetInstance().Log(a_Format, cLogger::llRegular, argList); + va_end(argList); +} + +void LOGINFO(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + cLogger::GetInstance().Log( a_Format, cLogger::llInfo, argList); + va_end(argList); +} + +void LOGWARN(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + cLogger::GetInstance().Log( a_Format, cLogger::llWarning, argList); + va_end(argList); +} + +void LOGERROR(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + cLogger::GetInstance().Log( a_Format, cLogger::llError, argList); + va_end(argList); +} + + + + diff --git a/src/LogDispacher.h b/src/Logger.h similarity index 51% rename from src/LogDispacher.h rename to src/Logger.h index 1472b392a..5e65de8a8 100644 --- a/src/LogDispacher.h +++ b/src/Logger.h @@ -2,8 +2,9 @@ #pragma once -namespace Logger +class cLogger { +public: enum eLogLevel { @@ -13,41 +14,32 @@ namespace Logger llError, }; - class cLogDispacher; - // Must be called before calling GetInstance in a multithreaded context - void InitiateMultithreading(); - - cLogDispacher & GetInstance(void); - - class cLoggerListener + class cListener { public: virtual void Log(AString a_Message, eLogLevel a_LogLevel) = 0; - - virtual ~cLoggerListener(){} + + virtual ~cListener(){} }; - class cLogDispacher - { - public: + void Log (const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) FORMATSTRING(2, 0); - void Log (const char * a_Format, Logger::eLogLevel a_LogLevel, va_list a_ArgList) FORMATSTRING(2, 0); + /** Logs the simple text message at the specified log level. */ + void LogSimple(AString a_Message, eLogLevel a_LogLevel = llRegular); - /** Logs the simple text message at the specified log level. */ - void LogSimple(AString a_Message, Logger::eLogLevel a_LogLevel = Logger::llRegular); + void AttachListener(cListener * a_Listener); + void DetachListener(cListener * a_Listener); - void AttachListener(Logger::cLoggerListener * a_Listener); - void DetachListener(Logger::cLoggerListener * a_Listener); + static cLogger & GetInstance(void); + // Must be called before calling GetInstance in a multithreaded context + static void InitiateMultithreading(); +private: - private: - - cCriticalSection m_CriticalSection; - std::vector m_LogListeners; - - }; + cCriticalSection m_CriticalSection; + std::vector m_LogListeners; -} +}; diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp new file mode 100644 index 000000000..d6567abe0 --- /dev/null +++ b/src/LoggerListeners.cpp @@ -0,0 +1,231 @@ + +#include "Globals.h" + +#include "LoggerListeners.h" + +#if defined(_WIN32) + #include // Needed for _isatty(), not available on Linux +#elif defined(__linux) && !defined(ANDROID_NDK) + #include // Needed for isatty() on Linux +#elif defined(ANDROID_NDK) + #include +#endif + + +#if defined(_WIN32) || (defined (__linux) && !defined(ANDROID_NDK)) + class cColouredConsoleListener + : public cLogger::cListener + { + + virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) = 0; + virtual void SetDefaultLogColour() = 0; + + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + SetLogColour(a_LogLevel); + puts(a_Message.c_str()); + SetDefaultLogColour(); + } + }; +#endif + +#ifdef _WIN32 + class cWindowsConsoleListener + : public cColouredConsoleListener + { + public: + cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) : + m_Console(a_Console), + m_DefaultConsoleAttrib(a_DefaultConsoleAttrib) + { + } + + #ifdef DEBUG + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + cColouredConsoleListener::Log(a_Message, a_LogLevel); + // In a Windows Debug build, output the log to debug console as well: + OutputDebugStringA(a_Message.c_str()); + } + #endif + + + virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override + { + // by default, gray on black + WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + switch (a_LogLevel) + { + case cLogger::llRegular: + // Gray on black + Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + case cLogger::llInfo: + // Yellow on black + Attrib = FOREGROUND_GREEN | ; + break; + case cLogger::llWarning: + // Red on black + Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case cLogger::llError: + // Black on red + Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; + break; + } + SetConsoleTextAttribute(m_Console, Attrib); + } + virtual void SetDefaultLogColour() override + { + SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); + } + private: + HANDLE m_Console; + WORD m_DefaultConsoleAttrib; + }; +#elif defined (__linux) && !defined(ANDROID_NDK) + class cLinuxConsoleListener + : public cColouredConsoleListener + { + public: + virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override + { + switch (a_LogLevel) + { + case cLogger::llRegular: + // Whatever the console default is + printf("\x1b[0m"); + break; + case cLogger::llInfo: + // Yellow on black + printf("\x1b[33;1m"); + break; + case cLogger::llWarning: + // Red on black + printf("\x1b[31;1m"); + break; + case cLogger::llError: + // Yellow on red + printf("\x1b[1;33;41;1m"); + break; + } + } + virtual void SetDefaultLogColour() override + { + // Whatever the console default is + printf("\x1b[0m"); + } + }; +#elif defined(ANDROID_NDK) + class cAndroidConsoleListener + : public cLogger::cListener + { + public: + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + android_LogPriority AndroidLogLevel; + switch (a_LogLevel) + { + case cLogger::llRegular: + AndroidLogLevel = ANDROID_LOG_VERBOSE; + break; + case cLogger::llInfo: + AndroidLogLevel = ANDROID_LOG_INFO; + break; + case cLogger::llWarning: + AndroidLogLevel = ANDROID_LOG_WARNING; + break; + case cLogger::llError: + AndroidLogLevel = ANDROID_LOG_ERROR; + break; + } + __android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str()); + } + }; +#endif + +class cVanillaCPPConsoleListener + : public cLogger::cListener +{ +public: + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override + { + AString LogLevelString; + switch (a_LogLevel) + { + case cLogger::llRegular: + LogLevelString = "Log"; + break; + case cLogger::llInfo: + LogLevelString = "Info"; + break; + case cLogger::llWarning: + LogLevelString = "Warning"; + break; + case cLogger::llError: + LogLevelString = "Error"; + break; + } + printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + } +}; + + + +cLogger::cListener * MakeConsoleListener() +{ + #ifdef _WIN32 + // See whether we are writing to a console the default console attrib: + bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); + if (ShouldColorOutput) + { + CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE Console = getStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(Console, &sbi); + WORD DefaultConsoleAttrib = sbi.wAttributes; + return new cWindowsConsoleListener(Console, DefaultConsoleAttrib); + } else { + return new cVanillaCPPConsoleListener(); + } + + #elif defined (__linux) && !defined(ANDROID_NDK) + // TODO: lookup terminal in terminfo + if (isatty(fileno(stdout))) + { + return new cLinuxConsoleListener(); + } else { + return new cVanillaCPPConsoleListener(); + } + #else + return new cVanillaCPPConsoleListener(); + #endif +} + +cFileListener::cFileListener() +{ + cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); + AString FileName; + FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL)); + m_File.Open(FileName, cFile::fmAppend); +} + +void cFileListener::Log(AString a_Message, cLogger::eLogLevel a_LogLevel) +{ + AString LogLevelString; + switch (a_LogLevel) + { + case cLogger::llRegular: + LogLevelString = "Log"; + break; + case cLogger::llInfo: + LogLevelString = "Info"; + break; + case cLogger::llWarning: + LogLevelString = "Warning"; + break; + case cLogger::llError: + LogLevelString = "Error"; + break; + } + m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); +} diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h new file mode 100644 index 000000000..4d2889a93 --- /dev/null +++ b/src/LoggerListeners.h @@ -0,0 +1,17 @@ + +#include "Logger.h" + +class cFileListener + : public cLogger::cListener +{ + public: + + cFileListener(); + cFileListener(AString a_Filename); + + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override; + private: + cFile m_File; +}; + +cLogger::cListener * MakeConsoleListener(); diff --git a/src/Root.cpp b/src/Root.cpp index 72048b631..ee0d9b835 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -18,7 +18,7 @@ #include "CommandOutput.h" #include "DeadlockDetect.h" #include "OSSupport/Timer.h" -#include "Listeners.h" +#include "LoggerListeners.h" #include "inifile/iniFile.h" @@ -106,10 +106,10 @@ void cRoot::Start(void) EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling #endif - Logger::cLoggerListener * consoleLogListener = Logger::MakeConsoleListener(); - Logger::cLoggerListener * fileLogListener = new Logger::cFileListener(); - Logger::GetInstance().AttachListener(consoleLogListener); - Logger::GetInstance().AttachListener(fileLogListener); + cLogger::cListener * consoleLogListener = MakeConsoleListener(); + cLogger::cListener * fileLogListener = new cFileListener(); + cLogger::GetInstance().AttachListener(consoleLogListener); + cLogger::GetInstance().AttachListener(fileLogListener); LOG("--- Started Log ---\n"); @@ -257,9 +257,9 @@ void cRoot::Start(void) LOG("--- Stopped Log ---"); - Logger::GetInstance().DetachListener(consoleLogListener); + cLogger::GetInstance().DetachListener(consoleLogListener); delete consoleLogListener; - Logger::GetInstance().DetachListener(fileLogListener); + cLogger::GetInstance().DetachListener(fileLogListener); delete fileLogListener; } diff --git a/src/main.cpp b/src/main.cpp index e40035538..86ecd4000 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -273,7 +273,7 @@ int main( int argc, char **argv) } } // for i - argv[] - Logger::InitiateMultithreading(); + cLogger::InitiateMultithreading(); #if !defined(ANDROID_NDK) try From 01c50eb53ab06f99fd08a2d599095e6dec683b60 Mon Sep 17 00:00:00 2001 From: Tycho Date: Tue, 12 Aug 2014 17:32:08 +0100 Subject: [PATCH 163/751] Fix messing rename --- src/Bindings/LuaFunctions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bindings/LuaFunctions.h b/src/Bindings/LuaFunctions.h index 6a645ed53..be1d9aaa9 100644 --- a/src/Bindings/LuaFunctions.h +++ b/src/Bindings/LuaFunctions.h @@ -1,6 +1,6 @@ #pragma once -#include "LogDispacher.h" +#include "Logger.h" #include // tolua_begin From 10e58f04da038a28626fee90d278c703d55f72b6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 12 Aug 2014 22:43:04 +0200 Subject: [PATCH 164/751] Fixed windows compilation and style issues. --- src/Logger.cpp | 56 ++++++++++++++---- src/LoggerListeners.cpp | 122 ++++++++++++++++++++++++++++++++++------ src/LoggerListeners.h | 28 ++++++--- src/OSSupport/File.h | 8 +-- 4 files changed, 177 insertions(+), 37 deletions(-) diff --git a/src/Logger.cpp b/src/Logger.cpp index e0ea973f8..572a0e160 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -2,6 +2,12 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "OSSupport/IsThread.h" +#ifdef _WIN32 + #include +#endif + + + cLogger & cLogger::GetInstance(void) @@ -10,35 +16,43 @@ cLogger & cLogger::GetInstance(void) return Instance; } + + + + void cLogger::InitiateMultithreading() { GetInstance(); } + + + + void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel) { time_t rawtime; - time ( &rawtime); + time(&rawtime); - struct tm* timeinfo; + struct tm * timeinfo; #ifdef _MSC_VER struct tm timeinforeal; timeinfo = &timeinforeal; localtime_s(timeinfo, &rawtime); #else - timeinfo = localtime( &rawtime); + timeinfo = localtime(&rawtime); #endif AString Line; #ifdef _DEBUG - Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); #else - Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); #endif cCSLock Lock(m_CriticalSection); - for(size_t i = 0; i < m_LogListeners.size(); i++) + for (size_t i = 0; i < m_LogListeners.size(); i++) { m_LogListeners[i]->Log(a_Message, a_LogLevel); } @@ -55,12 +69,20 @@ void cLogger::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList LogSimple(Message, a_LogLevel); } + + + + void cLogger::AttachListener(cListener * a_Listener) { cCSLock Lock(m_CriticalSection); m_LogListeners.push_back(a_Listener); } + + + + void cLogger::DetachListener(cListener * a_Listener) { cCSLock Lock(m_CriticalSection); @@ -69,10 +91,12 @@ void cLogger::DetachListener(cListener * a_Listener) + + //////////////////////////////////////////////////////////////////////////////// // Global functions -void LOG(const char* a_Format, ...) +void LOG(const char * a_Format, ...) { va_list argList; va_start(argList, a_Format); @@ -80,7 +104,11 @@ void LOG(const char* a_Format, ...) va_end(argList); } -void LOGINFO(const char* a_Format, ...) + + + + +void LOGINFO(const char * a_Format, ...) { va_list argList; va_start(argList, a_Format); @@ -88,7 +116,11 @@ void LOGINFO(const char* a_Format, ...) va_end(argList); } -void LOGWARN(const char* a_Format, ...) + + + + +void LOGWARN(const char * a_Format, ...) { va_list argList; va_start(argList, a_Format); @@ -96,7 +128,11 @@ void LOGWARN(const char* a_Format, ...) va_end(argList); } -void LOGERROR(const char* a_Format, ...) + + + + +void LOGERROR(const char * a_Format, ...) { va_list argList; va_start(argList, a_Format); diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index d6567abe0..912342a65 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -5,6 +5,7 @@ #if defined(_WIN32) #include // Needed for _isatty(), not available on Linux + #include #elif defined(__linux) && !defined(ANDROID_NDK) #include // Needed for isatty() on Linux #elif defined(ANDROID_NDK) @@ -29,10 +30,15 @@ }; #endif + + + + #ifdef _WIN32 class cWindowsConsoleListener : public cColouredConsoleListener { + typedef cColouredConsoleListener super; public: cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) : m_Console(a_Console), @@ -43,47 +49,65 @@ #ifdef DEBUG virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override { - cColouredConsoleListener::Log(a_Message, a_LogLevel); + super::Log(a_Message, a_LogLevel); // In a Windows Debug build, output the log to debug console as well: OutputDebugStringA(a_Message.c_str()); } #endif - - + + virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override { // by default, gray on black - WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; switch (a_LogLevel) { case cLogger::llRegular: + { // Gray on black - Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - break; + Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + } case cLogger::llInfo: + { // Yellow on black - Attrib = FOREGROUND_GREEN | ; - break; + Attrib = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + } case cLogger::llWarning: + { // Red on black Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; - break; + break; + } case cLogger::llError: - // Black on red + { + // Black on red Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; break; + } } SetConsoleTextAttribute(m_Console, Attrib); } + + virtual void SetDefaultLogColour() override { SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); } + private: + HANDLE m_Console; WORD m_DefaultConsoleAttrib; }; + + + #elif defined (__linux) && !defined(ANDROID_NDK) + + + class cLinuxConsoleListener : public cColouredConsoleListener { @@ -93,30 +117,46 @@ switch (a_LogLevel) { case cLogger::llRegular: + { // Whatever the console default is printf("\x1b[0m"); break; + } case cLogger::llInfo: + { // Yellow on black printf("\x1b[33;1m"); break; + } case cLogger::llWarning: + { // Red on black printf("\x1b[31;1m"); break; + } case cLogger::llError: + { // Yellow on red printf("\x1b[1;33;41;1m"); break; + } } } + + virtual void SetDefaultLogColour() override { // Whatever the console default is printf("\x1b[0m"); } }; + + + #elif defined(ANDROID_NDK) + + + class cAndroidConsoleListener : public cLogger::cListener { @@ -127,23 +167,36 @@ switch (a_LogLevel) { case cLogger::llRegular: + { AndroidLogLevel = ANDROID_LOG_VERBOSE; break; + } case cLogger::llInfo: + { AndroidLogLevel = ANDROID_LOG_INFO; break; + } case cLogger::llWarning: + { AndroidLogLevel = ANDROID_LOG_WARNING; break; + } case cLogger::llError: + { AndroidLogLevel = ANDROID_LOG_ERROR; break; + } } __android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str()); } }; + #endif + + + + class cVanillaCPPConsoleListener : public cLogger::cListener { @@ -154,17 +207,25 @@ public: switch (a_LogLevel) { case cLogger::llRegular: + { LogLevelString = "Log"; break; + } case cLogger::llInfo: + { LogLevelString = "Info"; break; + } case cLogger::llWarning: + { LogLevelString = "Warning"; break; + } case cLogger::llError: + { LogLevelString = "Error"; break; + } } printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); } @@ -172,7 +233,9 @@ public: -cLogger::cListener * MakeConsoleListener() + + +cLogger::cListener * MakeConsoleListener(void) { #ifdef _WIN32 // See whether we are writing to a console the default console attrib: @@ -180,12 +243,14 @@ cLogger::cListener * MakeConsoleListener() if (ShouldColorOutput) { CONSOLE_SCREEN_BUFFER_INFO sbi; - HANDLE Console = getStdHandle(STD_OUTPUT_HANDLE); + HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(Console, &sbi); WORD DefaultConsoleAttrib = sbi.wAttributes; return new cWindowsConsoleListener(Console, DefaultConsoleAttrib); - } else { - return new cVanillaCPPConsoleListener(); + } + else + { + return new cVanillaCPPConsoleListener; } #elif defined (__linux) && !defined(ANDROID_NDK) @@ -193,7 +258,9 @@ cLogger::cListener * MakeConsoleListener() if (isatty(fileno(stdout))) { return new cLinuxConsoleListener(); - } else { + } + else + { return new cVanillaCPPConsoleListener(); } #else @@ -201,7 +268,14 @@ cLogger::cListener * MakeConsoleListener() #endif } -cFileListener::cFileListener() + + + + +//////////////////////////////////////////////////////////////////////////////// +// cFileListener: + +cFileListener::cFileListener(void) { cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); AString FileName; @@ -209,23 +283,39 @@ cFileListener::cFileListener() m_File.Open(FileName, cFile::fmAppend); } + + + + void cFileListener::Log(AString a_Message, cLogger::eLogLevel a_LogLevel) { AString LogLevelString; switch (a_LogLevel) { case cLogger::llRegular: + { LogLevelString = "Log"; break; + } case cLogger::llInfo: + { LogLevelString = "Info"; break; + } case cLogger::llWarning: + { LogLevelString = "Warning"; break; + } case cLogger::llError: + { LogLevelString = "Error"; break; + } } m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); } + + + + diff --git a/src/LoggerListeners.h b/src/LoggerListeners.h index 4d2889a93..d300184b1 100644 --- a/src/LoggerListeners.h +++ b/src/LoggerListeners.h @@ -1,17 +1,31 @@ #include "Logger.h" + + + + class cFileListener : public cLogger::cListener { - public: +public: + + cFileListener(); + cFileListener(AString a_Filename); + + virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override; - cFileListener(); - cFileListener(AString a_Filename); - - virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override; - private: - cFile m_File; +private: + + cFile m_File; }; + + + + cLogger::cListener * MakeConsoleListener(); + + + + diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index 8891511c4..dfb38e839 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -60,10 +60,10 @@ public: /** The mode in which to open the file */ enum eMode { - fmRead, // Read-only. If the file doesn't exist, object will not be valid - fmWrite, // Write-only. If the file already exists, it will be overwritten - fmReadWrite, // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning - fmAppend // Write-only. If the file already exists cursor will be moved to the end of the file + fmRead, // Read-only. If the file doesn't exist, object will not be valid + fmWrite, // Write-only. If the file already exists, it will be overwritten + fmReadWrite, // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning + fmAppend // Write-only. If the file already exists cursor will be moved to the end of the file } ; /** Simple constructor - creates an unopened file object, use Open() to open / create a real file */ From e110f7226895b1629f72a52c7953d8f00a1f63c6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 09:53:33 +0200 Subject: [PATCH 165/751] 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 166/751] 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 60ea4bb937ba56c6dcaf57dda377beed972cf0a5 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 11:56:47 +0100 Subject: [PATCH 167/751] Removed unused method --- src/WebAdmin.cpp | 22 ---------------------- src/WebAdmin.h | 3 --- 2 files changed, 25 deletions(-) diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index ab6925e55..6882d7bc4 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -159,28 +159,6 @@ void cWebAdmin::Stop(void) -AString cWebAdmin::GetTemplate() -{ - AString retVal = ""; - - char SourceFile[] = "webadmin/template.html"; - - cFile f; - if (!f.Open(SourceFile, cFile::fmRead)) - { - return ""; - } - - // copy the file into the buffer: - f.ReadRestOfFile(retVal); - - return retVal; -} - - - - - void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { if (!a_Request.HasAuth()) diff --git a/src/WebAdmin.h b/src/WebAdmin.h index f48e8ce9e..aefc1d145 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -208,9 +208,6 @@ protected: /** The HTTP server which provides the underlying HTTP parsing, serialization and events */ cHTTPServer m_HTTPServer; - - AString GetTemplate(void); - /** Handles requests coming to the "/webadmin" or "/~webadmin" URLs */ void HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request); From 2321d2af41e935d8353b18592c29d58c766a5658 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 12:01:13 +0100 Subject: [PATCH 168/751] Fixed shadowing variable --- src/WebAdmin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index 6882d7bc4..23eedbd14 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -176,9 +176,9 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque } // Check if the contents should be wrapped in the template: - AString URL = a_Request.GetBareURL(); - ASSERT(URL.length() > 0); - bool ShouldWrapInTemplate = ((URL.length() > 1) && (URL[1] != '~')); + AString BareURL = a_Request.GetBareURL(); + ASSERT(BareURL.length() > 0); + bool ShouldWrapInTemplate = ((BareURL.length() > 1) && (BareURL[1] != '~')); // Retrieve the request data: cWebadminRequestData * Data = (cWebadminRequestData *)(a_Request.GetUserData()); @@ -193,7 +193,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque HTTPTemplateRequest TemplateRequest; TemplateRequest.Request.Username = a_Request.GetAuthUsername(); TemplateRequest.Request.Method = a_Request.GetMethod(); - TemplateRequest.Request.Path = URL.substr(1); + TemplateRequest.Request.Path = BareURL.substr(1); if (Data->m_Form.Finish()) { @@ -236,7 +236,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque return; } - AString BaseURL = GetBaseURL(URL); + AString BaseURL = GetBaseURL(BareURL); AString Menu; Template = "{CONTENT}"; AString FoundPlugin; From 8f7b9acb488a2dc4a9c34de499a3cd0e0829ef40 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 12:10:21 +0100 Subject: [PATCH 169/751] 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 170/751] 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 08c55ef98348b13f4375fe683337fbf3cc9a9122 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 13:27:56 +0200 Subject: [PATCH 171/751] Logger: Fixed missing timestamp in log messages. --- src/Logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Logger.cpp b/src/Logger.cpp index 572a0e160..cb528e8ab 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -54,7 +54,7 @@ void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel) cCSLock Lock(m_CriticalSection); for (size_t i = 0; i < m_LogListeners.size(); i++) { - m_LogListeners[i]->Log(a_Message, a_LogLevel); + m_LogListeners[i]->Log(Line, a_LogLevel); } } From 5921f78e523b3998e72f9c681b8211fd2bc99127 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 13:28:45 +0200 Subject: [PATCH 172/751] Logger: Fixed windows debug ODS logger, fixed-size file prefixes. --- src/LoggerListeners.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index 912342a65..b86ab4127 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -17,6 +17,7 @@ class cColouredConsoleListener : public cLogger::cListener { + protected: virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) = 0; virtual void SetDefaultLogColour() = 0; @@ -24,7 +25,7 @@ virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override { SetLogColour(a_LogLevel); - puts(a_Message.c_str()); + fputs(a_Message.c_str(), stdout); SetDefaultLogColour(); } }; @@ -46,7 +47,7 @@ { } - #ifdef DEBUG + #ifdef _DEBUG virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override { super::Log(a_Message, a_LogLevel); @@ -289,31 +290,31 @@ cFileListener::cFileListener(void) void cFileListener::Log(AString a_Message, cLogger::eLogLevel a_LogLevel) { - AString LogLevelString; + const char * LogLevelPrefix = "U "; switch (a_LogLevel) { case cLogger::llRegular: { - LogLevelString = "Log"; + LogLevelPrefix = " "; break; } case cLogger::llInfo: { - LogLevelString = "Info"; + LogLevelPrefix = "i "; break; } case cLogger::llWarning: { - LogLevelString = "Warning"; + LogLevelPrefix = "W "; break; } case cLogger::llError: { - LogLevelString = "Error"; + LogLevelPrefix = "E "; break; } } - m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + m_File.Printf("%s: %s", LogLevelPrefix, a_Message.c_str()); } From 36e918ce9bd546efa25987027a73e0f1d8fa192d Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Wed, 13 Aug 2014 13:31:19 +0200 Subject: [PATCH 173/751] File logger prefixes are 4 chars wide. --- src/LoggerListeners.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/LoggerListeners.cpp b/src/LoggerListeners.cpp index b86ab4127..836536cbd 100644 --- a/src/LoggerListeners.cpp +++ b/src/LoggerListeners.cpp @@ -290,31 +290,31 @@ cFileListener::cFileListener(void) void cFileListener::Log(AString a_Message, cLogger::eLogLevel a_LogLevel) { - const char * LogLevelPrefix = "U "; + const char * LogLevelPrefix = "Unkn "; switch (a_LogLevel) { case cLogger::llRegular: { - LogLevelPrefix = " "; + LogLevelPrefix = " "; break; } case cLogger::llInfo: { - LogLevelPrefix = "i "; + LogLevelPrefix = "info "; break; } case cLogger::llWarning: { - LogLevelPrefix = "W "; + LogLevelPrefix = "Warn "; break; } case cLogger::llError: { - LogLevelPrefix = "E "; + LogLevelPrefix = "Err "; break; } } - m_File.Printf("%s: %s", LogLevelPrefix, a_Message.c_str()); + m_File.Printf("%s%s", LogLevelPrefix, a_Message.c_str()); } From 781e1e6264794ec0fddccd37a76f7a78a3fa8b09 Mon Sep 17 00:00:00 2001 From: Tycho Date: Wed, 13 Aug 2014 13:03:56 +0100 Subject: [PATCH 174/751] 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 175/751] 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 176/751] 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 177/751] 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 178/751] 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 179/751] 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 180/751] 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 008c1cdaf436dec2d7a4a925c6a600570594d6a2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 14 Aug 2014 01:03:30 +0200 Subject: [PATCH 181/751] CheckBasicStyle checks the src folder as well. --- src/CMakeLists.txt | 2 +- src/Chunk.cpp | 26 ++++++++++++++++---------- src/Chunk.h | 2 +- src/World.cpp | 2 +- src/World.h | 2 +- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db9c61082..3994399f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,7 +234,7 @@ endif() # Generate a list of all source files: -set(ALLFILES "") +set(ALLFILES "${SRCS}" "${HDRS}") foreach(folder ${FOLDERS}) get_directory_property(FOLDER_SRCS DIRECTORY ${folder} DEFINITION SRCS) foreach (src ${FOLDER_SRCS}) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index a79a485a6..7bdf4196d 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -579,7 +579,7 @@ void cChunk::Tick(float a_Dt) } for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) - { + { if (!((*itr)->IsMob())) // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) { // Tick all entities in this chunk (except mobs): @@ -594,17 +594,19 @@ void cChunk::Tick(float a_Dt) itr = m_Entities.erase(itr); delete ToDelete; } - else if ((*itr)->IsWorldTravellingFrom(m_World)) // Remove all entities that are travelling to another world: + else if ((*itr)->IsWorldTravellingFrom(m_World)) { + // Remove all entities that are travelling to another world MarkDirty(); (*itr)->SetWorldTravellingFrom(NULL); itr = m_Entities.erase(itr); } - else if ( // If any entity moved out of the chunk, move it to the neighbor: + else if ( ((*itr)->GetChunkX() != m_PosX) || ((*itr)->GetChunkZ() != m_PosZ) ) { + // The entity moved out of the chunk, move it to the neighbor MarkDirty(); MoveEntityToNewChunk(*itr); itr = m_Entities.erase(itr); @@ -885,14 +887,14 @@ void cChunk::ApplyWeatherToTop() SetBlock(X, Height, Z, E_BLOCK_ICE, 0); } else if ( - (m_World->IsDeepSnowEnabled()) && - ( - (TopBlock == E_BLOCK_RED_ROSE) || - (TopBlock == E_BLOCK_YELLOW_FLOWER) || - (TopBlock == E_BLOCK_RED_MUSHROOM) || - (TopBlock == E_BLOCK_BROWN_MUSHROOM) - ) + (m_World->IsDeepSnowEnabled()) && + ( + (TopBlock == E_BLOCK_RED_ROSE) || + (TopBlock == E_BLOCK_YELLOW_FLOWER) || + (TopBlock == E_BLOCK_RED_MUSHROOM) || + (TopBlock == E_BLOCK_BROWN_MUSHROOM) ) + ) { SetBlock(X, Height, Z, E_BLOCK_SNOW, 0); } @@ -2142,10 +2144,14 @@ bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_Blo case E_BLOCK_DROPPER: case E_BLOCK_DISPENSER: case E_BLOCK_NOTE_BLOCK: + { break; + } default: + { // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out return false; + } } if (a_Callback.Item((cRedstonePoweredEntity *)*itr)) diff --git a/src/Chunk.h b/src/Chunk.h index 813a8b13f..72a1f6c95 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -241,7 +241,7 @@ public: bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible /** Calls the callback for the redstone powered entity at the specified coords; returns false if there's no redstone powered entity at those coords, true if found */ - bool DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback); + bool DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback); /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible diff --git a/src/World.cpp b/src/World.cpp index 5298f3b03..b357b8a23 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3327,7 +3327,7 @@ void cWorld::AddQueuedPlayers(void) cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) { - ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW? + ASSERT(std::find(m_Players.begin(), m_Players.end(), *itr) == m_Players.end()); // Is it already in the list? HOW? LOGD("Adding player %s to world \"%s\".", (*itr)->GetName().c_str(), m_WorldName.c_str()); m_Players.push_back(*itr); diff --git a/src/World.h b/src/World.h index 6df1758e9..578c9682b 100644 --- a/src/World.h +++ b/src/World.h @@ -235,7 +235,7 @@ public: void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) override; // tolua_export + virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) override; // tolua_export void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); From e3a74f379fc103f40e6bf85e626d7bac7db236af Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Thu, 14 Aug 2014 14:29:46 +0200 Subject: [PATCH 182/751] 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 183/751] 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 1f4a1383c2b261aa4644f8efeb31eedce4a62bf4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 15 Aug 2014 07:19:13 +0200 Subject: [PATCH 184/751] Removed an unneeded cast. --- src/OSSupport/File.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index af8a832f6..2194c46ee 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -259,7 +259,7 @@ int cFile::ReadRestOfFile(AString & a_Contents) size_t DataSize = GetSize() - Tell(); // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly - a_Contents.assign((size_t)DataSize, '\0'); + a_Contents.assign(DataSize, '\0'); return Read((void *)a_Contents.data(), DataSize); } From 0f631febfc3f670e8e9eb60ec4f89659ad7d0c71 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Fri, 15 Aug 2014 13:40:56 +0200 Subject: [PATCH 185/751] 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 186/751] 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 187/751] 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 188/751] 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 9395cf0bca15371b8dfdb7a444c1e9f7cca0252c Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 16 Aug 2014 18:02:16 +0200 Subject: [PATCH 189/751] First implementation of HOOK_SERVER_PING. --- src/Bindings/Plugin.h | 1 + src/Bindings/PluginLua.cpp | 20 ++++++++++++++++++++ src/Bindings/PluginLua.h | 1 + src/Bindings/PluginManager.cpp | 19 +++++++++++++++++++ src/Bindings/PluginManager.h | 2 ++ 5 files changed, 43 insertions(+) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 39d53674b..6f05af51b 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -91,6 +91,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) = 0; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; + virtual bool OnServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 0f3f25d75..066e050d6 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1193,6 +1193,26 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity +bool cPluginLua::OnServerPing(const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Username, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); + if (res) + { + return true; + } + } + return false; +} + + + + + bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 2cea644c1..2d98477f0 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -117,6 +117,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) override; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; + virtual bool OnServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 89bfe3566..b9d28205d 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1189,6 +1189,25 @@ bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectil +bool cPluginManager::CallHookServerPing(const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +{ + FIND_HOOK(HOOK_SERVER_PING); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnServerPing(a_Username, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { FIND_HOOK(HOOK_SPAWNED_ENTITY); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 44a94e316..104e4c7a9 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -120,6 +120,7 @@ public: HOOK_PRE_CRAFTING, HOOK_PROJECTILE_HIT_BLOCK, HOOK_PROJECTILE_HIT_ENTITY, + HOOK_SERVER_PING, HOOK_SPAWNED_ENTITY, HOOK_SPAWNED_MONSTER, HOOK_SPAWNING_ENTITY, @@ -225,6 +226,7 @@ public: bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos); bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); + bool CallHookServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); From a68c70c900d0f3b3842d78af49423890f29af180 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 16 Aug 2014 18:44:14 +0200 Subject: [PATCH 190/751] Better OnPlayerMoving hook. --- src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 4 ++-- src/Bindings/PluginLua.h | 2 +- src/Bindings/PluginManager.cpp | 4 ++-- src/Bindings/PluginManager.h | 2 +- src/Entities/Player.cpp | 12 ++++++++++-- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 39d53674b..2cc5cade3 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 OnPlayerMoved (cPlayer & a_Player) = 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 0f3f25d75..37db78994 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -835,14 +835,14 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block -bool cPluginLua::OnPlayerMoved(cPlayer & a_Player) +bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) { cCSLock Lock(m_CriticalSection); bool res = false; 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, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Player, &a_OldPosition, &a_NewPosition, cLuaState::Return, res); if (res) { return true; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 2cea644c1..6df86f7a1 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -98,7 +98,7 @@ 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 OnPlayerMoved (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 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; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 89bfe3566..dbc359f0e 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -849,14 +849,14 @@ bool cPluginManager::CallHookPlayerLeftClick(cPlayer & a_Player, int a_BlockX, i -bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player) +bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) { FIND_HOOK(HOOK_PLAYER_MOVING); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnPlayerMoved(a_Player)) + if ((*itr)->OnPlayerMoving(a_Player, a_OldPosition, a_NewPosition)) { return true; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 44a94e316..e0573f386 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -206,7 +206,7 @@ public: bool CallHookPlayerFishing (cPlayer & a_Player, cItems a_Reward); bool CallHookPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel); bool CallHookPlayerJoined (cPlayer & a_Player); - bool CallHookPlayerMoving (cPlayer & a_Player); + bool CallHookPlayerMoving (cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition); bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); bool CallHookPlayerPlacedBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerPlacingBlock (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); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 4398a5bf3..ab4ff3161 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -225,16 +225,24 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) SendExperience(); } + bool CanMove = true; if (!GetPosition().EqualsEps(m_LastPos, 0.01)) // Non negligible change in position from last tick? { // Apply food exhaustion from movement: ApplyFoodExhaustionFromMovement(); - cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this); + if (cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this, m_LastPos, GetPosition())) + { + CanMove = false; + TeleportToCoords(m_LastPos.x, m_LastPos.y, m_LastPos.z); + } m_ClientHandle->StreamChunks(); } - BroadcastMovementUpdate(m_ClientHandle); + if (CanMove) + { + BroadcastMovementUpdate(m_ClientHandle); + } if (m_Health > 0) // make sure player is alive { From 6c8baf66c81e043710e70d8de584ab93d1cbbfc8 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 16 Aug 2014 18:49:24 +0200 Subject: [PATCH 191/751] Updated HOOK_PLAYER_MOVING documentation. --- MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua b/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua index 2756529ef..4385bf94d 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnPlayerMoving.lua @@ -11,9 +11,11 @@ return Params = { { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has moved. The object already has the new position stored in it." }, + { Name = "OldPosition", Type = "{{Vector3d}}", Notes = "The old position." }, + { Name = "NewPosition", Type = "{{Vector3d}}", Notes = "The new position." }, }, Returns = [[ - If the function returns true, movement is prohibited. FIXME: The player's client is not informed.

+ If the function returns true, movement is prohibited.

If the function returns false or no value, other plugins' callbacks are called and finally the new position is permanently stored in the cPlayer object.

From 9522bd842ea845cc37b4d2a60333453c12b024a4 Mon Sep 17 00:00:00 2001 From: STRWarrior Date: Mon, 18 Aug 2014 12:53:36 +0200 Subject: [PATCH 192/751] SwamplandM: Fixed sometimes having no mountains. --- src/Generating/HeiGen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index ba11b31b4..c3f3b38a9 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -432,7 +432,7 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] = /* biExtremeHillsM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 131 /* biFlowerForest */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 132 /* biTaigaM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 133 - /* biSwamplandM */ { 1.0f, 2.0f, 1.10f, 5.0f, 0.01f, 8.0f, 60}, // 134 + /* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134 // Biomes 135 .. 139 unused, 5 empty placeholders here: {}, {}, {}, {}, {}, // 135 .. 139 From 80559406f99bd32de066c8a80b9f920b8b57b8f1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 17 Aug 2014 22:47:00 +0200 Subject: [PATCH 193/751] Player saving creates the "players" folder, if needed. Fixes #1268. --- src/Entities/Player.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index ab4ff3161..0b13e62a9 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1842,6 +1842,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) bool cPlayer::SaveToDisk() { + cFile::CreateFolder(FILE_IO_PREFIX + AString("players/")); // Create the "players" folder, if it doesn't exist yet (#1268) cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.substr(0, 2)); // create the JSON data From c70886a7124e5940b67cb4f1b4593f103f2707d8 Mon Sep 17 00:00:00 2001 From: Christophe Piveteau Date: Mon, 18 Aug 2014 01:57:44 +0200 Subject: [PATCH 194/751] 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 e4fc05574bc4d888a8794d68c518e5242c494f69 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 18 Aug 2014 22:48:15 +0200 Subject: [PATCH 195/751] Player: Silenced a few type conversion warnings. --- src/Entities/Player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0b13e62a9..32290885d 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -892,7 +892,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) Pickups.Add(cItem(E_ITEM_RED_APPLE)); } - m_Stats.AddValue(statItemsDropped, Pickups.Size()); + m_Stats.AddValue(statItemsDropped, (StatValue)Pickups.Size()); m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! @@ -1618,7 +1618,7 @@ void cPlayer::TossPickup(const cItem & a_Item) void cPlayer::TossItems(const cItems & a_Items) { - m_Stats.AddValue(statItemsDropped, a_Items.Size()); + m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size()); double vX = 0, vY = 0, vZ = 0; EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); From d3fd63c9eb5f783da0186efcef81a5b0eb9338d6 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Tue, 19 Aug 2014 12:38:15 +0200 Subject: [PATCH 196/751] Added some Enchantments - Bow enchantments: Infinity, Flame and Power - Sword and tools enchantments: Fire Aspect, Bane of Arthropods, Smite, Sharpness --- src/Entities/ArrowEntity.cpp | 26 +++++++++++++-- src/Entities/ArrowEntity.h | 7 ++-- src/Entities/Entity.cpp | 62 +++++++++++++++++++++++++++++++++++- src/Items/ItemBow.h | 12 ++++++- 4 files changed, 100 insertions(+), 7 deletions(-) diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 913519c4c..c4fd378fb 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -18,6 +18,7 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a m_HitGroundTimer(0), m_HasTeleported(false), m_bIsCollected(false), + m_Creator(a_Creator), m_HitBlockPos(Vector3i(0, 0, 0)) { SetSpeed(a_Speed); @@ -43,6 +44,7 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_HitGroundTimer(0), m_HasTeleported(false), m_bIsCollected(false), + m_Creator(&a_Player), m_HitBlockPos(0, 0, 0) { if (a_Player.IsGameModeCreative()) @@ -68,9 +70,6 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const } - - - void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001)) @@ -90,6 +89,13 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa // Broadcast arrow hit sound m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + + if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && (m_TicksLeftBurning > 0)) + { + m_World->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); + m_World->SpawnPrimedTNT(X, Y, Z); + } + } @@ -103,8 +109,22 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); } + LOGD("Arrow hit an entity"); + + int PowerLevel = m_Creator->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPower); + if (PowerLevel > 0) + { + LOGD("Arrow hit an entity 2"); + int ExtraDamage = 0.25 * (PowerLevel + 1); + Damage += ceil(ExtraDamage); + } a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + if (m_TicksLeftBurning > 0) + { + a_EntityHit.StartBurning(100); + } + // Broadcast successful hit sound GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index 4bfcb1f6d..2ea6e9fde 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -10,6 +10,7 @@ + // tolua_begin class cArrowEntity : @@ -46,7 +47,7 @@ public: /// Returns the damage modifier coeff. double GetDamageCoeff(void) const { return m_DamageCoeff; } - + /// Sets the damage modifier coeff void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } @@ -89,7 +90,9 @@ protected: /// If true, the arrow is in the process of being collected - don't go to anyone else bool m_bIsCollected; - + + cEntity * m_Creator; + /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air Vector3i m_HitBlockPos; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 32f220897..398f7703b 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -316,8 +316,68 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) // IsOnGround() only is false if the player is moving downwards // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) - if (!Player->IsOnGround()) + + cEnchantments Enchantments = Player->GetEquippedItem().m_Enchantments; + + int SharpnessLevel = Enchantments.GetLevel(cEnchantments::enchSharpness); + int SmiteLevel = Enchantments.GetLevel(cEnchantments::enchSmite); + int BaneOfArthropodsLevel = Enchantments.GetLevel(cEnchantments::enchBaneOfArthropods); + + if (SharpnessLevel > 0) { + a_TDI.RawDamage += 1.25 * SharpnessLevel; + } + else if (SmiteLevel > 0) + { + if (IsMob()) + { + cMonster * Monster = (cMonster *)this; + switch (Monster->GetMobType()) + { + case cMonster::mtSkeleton: + case cMonster::mtZombie: + case cMonster::mtWither: + case cMonster::mtZombiePigman: + { + a_TDI.RawDamage += 2.5 * SmiteLevel; + break; + } + } + } + } + else if (BaneOfArthropodsLevel > 0) + { + if (IsMob()) + { + cMonster * Monster = (cMonster *)this; + switch (Monster->GetMobType()) + { + case cMonster::mtSpider: + case cMonster::mtCaveSpider: + case cMonster::mtSilverfish: + { + a_TDI.RawDamage += 2.5 * BaneOfArthropodsLevel; + break; + } + } + } + } + + int FireAspectLevel = Enchantments.GetLevel(cEnchantments::enchFireAspect); + if (FireAspectLevel > 0) + { + int BurnTicks = 3; + + if (FireAspectLevel > 1) + { + BurnTicks += 4 * (FireAspectLevel - 1); + } + + StartBurning(BurnTicks * 20); + } + + if (!Player->IsOnGround()) + { if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack)) { a_TDI.FinalDamage += 2; diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index fdc24689c..0fc0f0920 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -75,7 +75,6 @@ public: Arrow = NULL; return; } - a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); if (!a_Player->IsGameModeCreative()) { @@ -83,8 +82,19 @@ public: { a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW)); } + else + { + Arrow->SetPickupState(cArrowEntity::ePickupState::psNoPickup); + } + + a_Player->UseEquippedItem(); } + + if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0) + { + Arrow->StartBurning(100); + } } } ; From 1897f678f93bb038fdc4caf1fb2995a28ef8f92e Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Tue, 19 Aug 2014 16:08:17 +0200 Subject: [PATCH 197/751] Added more enchantments and some fixes - Removed Debug messages - Added Punch enchantment effect - Added Silk Touch enchantment - Added Unbreaking enchantment effect --- src/Blocks/BlockHandler.cpp | 32 ++++++++++++++++++++++++++++---- src/Blocks/BlockIce.h | 24 ++++++++++++------------ src/Entities/ArrowEntity.cpp | 22 ++++++++++++++++++---- src/Entities/ArrowEntity.h | 1 + src/Entities/Entity.cpp | 25 ++++++++++++++++++++++--- src/Entities/Player.cpp | 20 ++++++++++++++++++++ 6 files changed, 101 insertions(+), 23 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 52f7dd608..3c85a31e0 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -424,19 +424,43 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac cItems Pickups; NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (a_CanDrop) + // Thanks to daniel0916 + cPlayer * Player = (cPlayer *)a_Digger; + cEnchantments Enchantments = Player->GetInventory().GetEquippedItem().m_Enchantments; + if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) { - if (!a_DropVerbatim) + BLOCKTYPE Type = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + if (Type == E_BLOCK_CAKE || Type == E_BLOCK_CARROTS || Type == E_BLOCK_COCOA_POD || Type == E_BLOCK_DOUBLE_STONE_SLAB || + Type == E_BLOCK_DOUBLE_WOODEN_SLAB || Type == E_BLOCK_FIRE || Type == E_BLOCK_FARMLAND || Type == E_BLOCK_MELON_STEM || + Type == E_BLOCK_MOB_SPAWNER || Type == E_BLOCK_NETHER_WART || Type == E_BLOCK_POTATOES || Type == E_BLOCK_PUMPKIN_STEM || + Type == E_BLOCK_SNOW || Type == E_BLOCK_SUGARCANE || Type == E_BLOCK_TALL_GRASS || Type == E_BLOCK_CROPS + ) { + // Silktouch can't be used for this blocks ConvertToPickups(Pickups, Meta); } else { - // TODO: Add a proper overridable function for this Pickups.Add(m_BlockType, 1, Meta); } } - + else + { + if (a_CanDrop) + { + if (!a_DropVerbatim) + { + ConvertToPickups(Pickups, Meta); + } + else + { + // TODO: Add a proper overridable function for this + Pickups.Add(m_BlockType, 1, Meta); + } + } + + } + // Allow plugins to modify the pickups: a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups); diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index c38630fe3..cfe1d179f 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -30,18 +30,18 @@ public: { return; } - - BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); - if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) + + cEnchantments Enchantments = a_Player->GetInventory().GetEquippedItem().m_Enchantments; + if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) == 0) { - return; + BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) + { + return; + } + + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0); + // This is called later than the real destroying of this ice block } - - a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0); - // This is called later than the real destroying of this ice block } -} ; - - - - +} ; \ No newline at end of file diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index c4fd378fb..e71f30a66 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -109,18 +109,32 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); } - LOGD("Arrow hit an entity"); int PowerLevel = m_Creator->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPower); if (PowerLevel > 0) { - LOGD("Arrow hit an entity 2"); int ExtraDamage = 0.25 * (PowerLevel + 1); Damage += ceil(ExtraDamage); } - a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + + int KnockbackAmount = 1; + int PunchLevel = m_Creator->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch); + if (PunchLevel > 0) + { + Vector3f LookVector = m_Creator->GetLookVector(); + Vector3f FinalSpeed = Vector3f(0, 0, 0); + switch (PunchLevel) + { + case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); + case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); + default: break; + } + a_EntityHit.SetSpeed(FinalSpeed); + } + + a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); - if (m_TicksLeftBurning > 0) + if ((m_TicksLeftBurning > 0 && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())) { a_EntityHit.StartBurning(100); } diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index 2ea6e9fde..553bcb6e7 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -91,6 +91,7 @@ protected: /// If true, the arrow is in the process of being collected - don't go to anyone else bool m_bIsCollected; + // Stores the creator from that arrow cEntity * m_Creator; /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 398f7703b..05bad3a78 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -316,7 +316,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) // IsOnGround() only is false if the player is moving downwards // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) - + // Thanks to daniel0916 cEnchantments Enchantments = Player->GetEquippedItem().m_Enchantments; int SharpnessLevel = Enchantments.GetLevel(cEnchantments::enchSharpness); @@ -372,8 +372,27 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { BurnTicks += 4 * (FireAspectLevel - 1); } + if (!IsMob() && !IsSubmerged() && !IsSwimming()) + { + StartBurning(BurnTicks * 20); + } + else if (IsMob() && !IsSubmerged() && !IsSwimming()) + { + cMonster * Monster = (cMonster *)this; + switch (Monster->GetMobType()) + { + case cMonster::mtGhast: + case cMonster::mtZombiePigman: + case cMonster::mtMagmaCube: + { + + break; + }; + default:StartBurning(BurnTicks * 20); + } + } - StartBurning(BurnTicks * 20); + } if (!Player->IsOnGround()) @@ -410,7 +429,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case 2: AdditionalSpeed.Set(8, 0.3, 8); break; default: break; } - AddSpeed(a_TDI.Knockback + AdditionalSpeed); + SetSpeed(a_TDI.Knockback + AdditionalSpeed); } m_World->BroadcastEntityStatus(*this, esGenericHurt); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index ab4ff3161..c1031907d 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -17,6 +17,7 @@ #include "../Chunk.h" #include "../Items/ItemHandler.h" #include "../Vector3.h" +#include "../FastRandom.h" #include "../WorldStorage/StatSerializer.h" #include "../CompositeChat.h" @@ -1962,7 +1963,26 @@ void cPlayer::UseEquippedItem(int a_Amount) { return; } + cItem Item = GetEquippedItem(); + int UnbreakingLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking); + if (UnbreakingLevel > 0) + { + int chance; + if (ItemCategory::IsArmor(Item.m_ItemType)) + { + chance = 60 + (40 / (UnbreakingLevel + 1)); + } + else + { + chance = 100 / (UnbreakingLevel + 1); + } + cFastRandom Random; + if (Random.NextInt(100) <= chance) + { + return; + } + } if (GetInventory().DamageEquippedItem(a_Amount)) { m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); From 07350de514cebd9009f5fbdb5774aa8f1266bdb3 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Tue, 19 Aug 2014 16:47:33 +0200 Subject: [PATCH 198/751] Changed if for switch --- src/Blocks/BlockHandler.cpp | 33 ++++++++++++++++++++++----------- src/Blocks/BlockIce.h | 2 +- src/Entities/Entity.cpp | 5 ++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 3c85a31e0..1d537b125 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -430,18 +430,29 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) { BLOCKTYPE Type = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); - if (Type == E_BLOCK_CAKE || Type == E_BLOCK_CARROTS || Type == E_BLOCK_COCOA_POD || Type == E_BLOCK_DOUBLE_STONE_SLAB || - Type == E_BLOCK_DOUBLE_WOODEN_SLAB || Type == E_BLOCK_FIRE || Type == E_BLOCK_FARMLAND || Type == E_BLOCK_MELON_STEM || - Type == E_BLOCK_MOB_SPAWNER || Type == E_BLOCK_NETHER_WART || Type == E_BLOCK_POTATOES || Type == E_BLOCK_PUMPKIN_STEM || - Type == E_BLOCK_SNOW || Type == E_BLOCK_SUGARCANE || Type == E_BLOCK_TALL_GRASS || Type == E_BLOCK_CROPS - ) + switch (Type) { - // Silktouch can't be used for this blocks - ConvertToPickups(Pickups, Meta); - } - else - { - Pickups.Add(m_BlockType, 1, Meta); + case E_BLOCK_CAKE: + case E_BLOCK_CARROTS: + case E_BLOCK_COCOA_POD: + case E_BLOCK_DOUBLE_STONE_SLAB: + case E_BLOCK_DOUBLE_WOODEN_SLAB: + case E_BLOCK_FIRE: + case E_BLOCK_FARMLAND: + case E_BLOCK_MELON_STEM: + case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_NETHER_WART: + case E_BLOCK_POTATOES: + case E_BLOCK_PUMPKIN_STEM: + case E_BLOCK_SNOW: + case E_BLOCK_SUGARCANE: + case E_BLOCK_TALL_GRASS: + case E_BLOCK_CROPS: + { + // Silktouch can't be used for this blocks + ConvertToPickups(Pickups, Meta); + }; + default: Pickups.Add(m_BlockType, 1, Meta); } } else diff --git a/src/Blocks/BlockIce.h b/src/Blocks/BlockIce.h index cfe1d179f..47a84e5a7 100644 --- a/src/Blocks/BlockIce.h +++ b/src/Blocks/BlockIce.h @@ -44,4 +44,4 @@ public: // This is called later than the real destroying of this ice block } } -} ; \ No newline at end of file +} ; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 05bad3a78..4316b48e9 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -384,11 +384,10 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case cMonster::mtGhast: case cMonster::mtZombiePigman: case cMonster::mtMagmaCube: - { - + { break; }; - default:StartBurning(BurnTicks * 20); + default: StartBurning(BurnTicks * 20); } } From 949aa2f3836cfa2b64ab5104b4b4103c4e2ad537 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 19 Aug 2014 17:34:11 +0200 Subject: [PATCH 199/751] 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 596203e692e6322c7f989b1625cbe03dc1eb6a6c Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Tue, 19 Aug 2014 17:57:32 +0200 Subject: [PATCH 200/751] Fixes - Changed m_TicksLeftBurning > 0 for IsOnFire() - Tried to do the changes in BlockHandler.cpp - Removed m_Creator in ArrowEntity - Added m_Enchantments in ProjectileEntity CreatorData - Added blank lines between functions --- src/Blocks/BlockHandler.cpp | 70 +++++++++++++++---------------- src/Entities/ArrowEntity.cpp | 15 +++---- src/Entities/ArrowEntity.h | 3 -- src/Entities/ProjectileEntity.cpp | 5 ++- src/Entities/ProjectileEntity.h | 6 ++- src/Items/ItemBow.h | 2 +- 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 1d537b125..d6be99f83 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -427,49 +427,49 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac // Thanks to daniel0916 cPlayer * Player = (cPlayer *)a_Digger; cEnchantments Enchantments = Player->GetInventory().GetEquippedItem().m_Enchantments; - if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) + + if (a_CanDrop) { - BLOCKTYPE Type = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); - switch (Type) + if (!a_DropVerbatim) { - case E_BLOCK_CAKE: - case E_BLOCK_CARROTS: - case E_BLOCK_COCOA_POD: - case E_BLOCK_DOUBLE_STONE_SLAB: - case E_BLOCK_DOUBLE_WOODEN_SLAB: - case E_BLOCK_FIRE: - case E_BLOCK_FARMLAND: - case E_BLOCK_MELON_STEM: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_NETHER_WART: - case E_BLOCK_POTATOES: - case E_BLOCK_PUMPKIN_STEM: - case E_BLOCK_SNOW: - case E_BLOCK_SUGARCANE: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_CROPS: + if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) { - // Silktouch can't be used for this blocks - ConvertToPickups(Pickups, Meta); - }; - default: Pickups.Add(m_BlockType, 1, Meta); - } - } - else - { - if (a_CanDrop) - { - if (!a_DropVerbatim) - { - ConvertToPickups(Pickups, Meta); + switch (m_BlockType) + { + case E_BLOCK_CAKE: + case E_BLOCK_CARROTS: + case E_BLOCK_COCOA_POD: + case E_BLOCK_DOUBLE_STONE_SLAB: + case E_BLOCK_DOUBLE_WOODEN_SLAB: + case E_BLOCK_FIRE: + case E_BLOCK_FARMLAND: + case E_BLOCK_MELON_STEM: + case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_NETHER_WART: + case E_BLOCK_POTATOES: + case E_BLOCK_PUMPKIN_STEM: + case E_BLOCK_SNOW: + case E_BLOCK_SUGARCANE: + case E_BLOCK_TALL_GRASS: + case E_BLOCK_CROPS: + { + // Silktouch can't be used for this blocks + ConvertToPickups(Pickups, Meta); + break; + }; + default: Pickups.Add(m_BlockType, 1, Meta); + } } else { - // TODO: Add a proper overridable function for this - Pickups.Add(m_BlockType, 1, Meta); + ConvertToPickups(Pickups, Meta); } } - + else + { + // TODO: Add a proper overridable function for this + Pickups.Add(m_BlockType, 1, Meta); + } } // Allow plugins to modify the pickups: diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index e71f30a66..12149b297 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -18,7 +18,6 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a m_HitGroundTimer(0), m_HasTeleported(false), m_bIsCollected(false), - m_Creator(a_Creator), m_HitBlockPos(Vector3i(0, 0, 0)) { SetSpeed(a_Speed); @@ -44,7 +43,6 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_HitGroundTimer(0), m_HasTeleported(false), m_bIsCollected(false), - m_Creator(&a_Player), m_HitBlockPos(0, 0, 0) { if (a_Player.IsGameModeCreative()) @@ -70,6 +68,9 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const } + + + void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001)) @@ -90,7 +91,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa // Broadcast arrow hit sound m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && (m_TicksLeftBurning > 0)) + if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && (IsOnFire())) { m_World->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); m_World->SpawnPrimedTNT(X, Y, Z); @@ -110,7 +111,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); } - int PowerLevel = m_Creator->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPower); + int PowerLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPower); if (PowerLevel > 0) { int ExtraDamage = 0.25 * (PowerLevel + 1); @@ -118,10 +119,10 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) } int KnockbackAmount = 1; - int PunchLevel = m_Creator->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch); + int PunchLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPunch); if (PunchLevel > 0) { - Vector3f LookVector = m_Creator->GetLookVector(); + Vector3f LookVector = Vector3d(0, 0, 0); Vector3f FinalSpeed = Vector3f(0, 0, 0); switch (PunchLevel) { @@ -134,7 +135,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); - if ((m_TicksLeftBurning > 0 && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())) + if ((IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())) { a_EntityHit.StartBurning(100); } diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index 553bcb6e7..a1e7a17e7 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -91,9 +91,6 @@ protected: /// If true, the arrow is in the process of being collected - don't go to anyone else bool m_bIsCollected; - // Stores the creator from that arrow - cEntity * m_Creator; - /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air Vector3i m_HitBlockPos; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 43023ec28..acc9bd674 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -222,7 +222,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a m_ProjectileKind(a_Kind), m_CreatorData( ((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1), - ((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : "") + ((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""), + ((a_Creator != NULL) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments()) ), m_IsInGround(false) { @@ -235,7 +236,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) : super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height), m_ProjectileKind(a_Kind), - m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""), + m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "", a_Creator->GetEquippedWeapon().m_Enchantments), m_IsInGround(false) { SetSpeed(a_Speed); diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 0ebc32f36..58dc38702 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -94,14 +94,16 @@ protected: */ struct CreatorData { - CreatorData(int a_UniqueID, const AString & a_Name) : + CreatorData(int a_UniqueID, const AString & a_Name, cEnchantments a_Enchantments) : m_UniqueID(a_UniqueID), - m_Name(a_Name) + m_Name(a_Name), + m_Enchantments(a_Enchantments) { } const int m_UniqueID; AString m_Name; + cEnchantments m_Enchantments; }; /** The type of projectile I am */ diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 0fc0f0920..f29cc5d59 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -84,7 +84,7 @@ public: } else { - Arrow->SetPickupState(cArrowEntity::ePickupState::psNoPickup); + Arrow->SetPickupState(cArrowEntity::psNoPickup); } From 5008eb8c8348ad2664158a8a815ef6851d874367 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Tue, 19 Aug 2014 18:40:42 +0200 Subject: [PATCH 201/751] Changed if in BlockHandler --- src/Blocks/BlockHandler.cpp | 7 ++----- src/Entities/Entity.cpp | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index d6be99f83..2238a68a0 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -424,15 +424,12 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac cItems Pickups; NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - // Thanks to daniel0916 - cPlayer * Player = (cPlayer *)a_Digger; - cEnchantments Enchantments = Player->GetInventory().GetEquippedItem().m_Enchantments; - if (a_CanDrop) { if (!a_DropVerbatim) { - if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) + cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments; + if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && (a_Digger->IsPlayer())) { switch (m_BlockType) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4316b48e9..54e4cf4f5 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -316,7 +316,6 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) // IsOnGround() only is false if the player is moving downwards // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) - // Thanks to daniel0916 cEnchantments Enchantments = Player->GetEquippedItem().m_Enchantments; int SharpnessLevel = Enchantments.GetLevel(cEnchantments::enchSharpness); From b5ffe06f884221f98407910bdd30baf533d84970 Mon Sep 17 00:00:00 2001 From: Howaner Date: Tue, 19 Aug 2014 22:14:37 +0200 Subject: [PATCH 202/751] Code formatting fixes. --- src/Blocks/BlockBigFlower.h | 6 ++--- src/Blocks/BlockCake.h | 2 +- src/Blocks/BlockDirt.h | 2 +- src/Blocks/BlockFarmland.h | 5 +--- src/Blocks/BlockFenceGate.h | 1 + src/Blocks/BlockFire.h | 25 +++++++++++------- src/Blocks/BlockFlower.h | 2 +- src/Blocks/BlockGlowstone.h | 6 ++--- src/Blocks/BlockHandler.cpp | 6 ++--- src/Blocks/BlockMelon.h | 4 +-- src/Blocks/BlockNewLeaves.h | 42 ------------------------------ src/Blocks/BlockNote.h | 13 --------- src/Blocks/BlockOre.h | 40 ++++++++-------------------- src/Blocks/BlockPlanks.h | 3 +-- src/Blocks/BlockPortal.h | 8 +++--- src/Blocks/BlockPressurePlate.h | 4 +-- src/Blocks/BlockQuartz.h | 1 + src/Blocks/BlockRedstone.h | 4 +-- src/Blocks/BlockRedstoneRepeater.h | 6 ++--- src/Blocks/BlockStairs.h | 20 +++++++------- src/Blocks/BlockSugarcane.h | 1 + src/Blocks/BlockTorch.h | 4 +-- src/Blocks/BlockTrapdoor.h | 9 ++++--- src/Blocks/BlockTripwireHook.h | 10 +++---- src/Blocks/BlockVine.h | 6 ++--- src/Chunk.cpp | 1 + src/Items/ItemGoldenApple.h | 2 +- src/Items/ItemShovel.h | 1 - src/World.cpp | 1 + 29 files changed, 83 insertions(+), 152 deletions(-) delete mode 100644 src/Blocks/BlockNewLeaves.h delete mode 100644 src/Blocks/BlockNote.h diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index 0b6ac9d8a..72e552dee 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -37,7 +37,7 @@ public: { NIBBLETYPE Meta = a_BlockMeta & 0x7; - if ((Meta == 2) || (Meta == 3)) + if ((Meta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || (Meta == E_META_BIG_FLOWER_LARGE_FERN)) { return; } @@ -63,11 +63,11 @@ public: if (r1.randInt(10) == 5) { cItems Pickups; - if (FlowerMeta == 2) + if (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) { Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1); } - else if (FlowerMeta == 3) + else if (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN) { Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2); } diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h index 36e133388..f05f468e5 100644 --- a/src/Blocks/BlockCake.h +++ b/src/Blocks/BlockCake.h @@ -19,7 +19,7 @@ public: { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (!a_Player->Feed(2, 0.1)) + if (!a_Player->Feed(2, 0.4)) { return; } diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index 2d4fccbac..d458c6062 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -81,7 +81,7 @@ public: Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta)) { - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread)) + if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(Chunk->GetWorld(), Chunk->GetPosX() * cChunkDef::Width + BlockX, BlockY, Chunk->GetPosZ() * cChunkDef::Width + BlockZ, ssGrassSpread)) { Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0); } diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index ed0592acd..bb624e54f 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -54,10 +54,7 @@ public: BLOCKTYPE * BlockTypes = Area.GetBlockTypes(); for (size_t i = 0; i < NumBlocks; i++) { - if ( - (BlockTypes[i] == E_BLOCK_WATER) || - (BlockTypes[i] == E_BLOCK_STATIONARY_WATER) - ) + if (IsBlockWater(BlockTypes[i])) { Found = true; break; diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index 433531275..ae99a4f94 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -35,6 +35,7 @@ public: NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetYaw()); OldMetaData ^= 4; // Toggle the gate + if ((OldMetaData & 1) == (NewMetaData & 1)) { // Standing in front of the gate - apply new direction diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index f52825362..c6a3e62cf 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -60,8 +60,8 @@ public: return "step.wood"; } - /// Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border - /// Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding + /** Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border + Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding */ int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, int MaxY = 0) { if (a_ChunkInterface.GetBlock(X, Y, Z) != E_BLOCK_OBSIDIAN) @@ -91,13 +91,12 @@ public: return newY; } } - else { return 0; } } return 0; } - /// Evaluates if coords have a valid border on top, based on MaxY + /** Evaluates if coords have a valid border on top, based on MaxY */ bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) { for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners @@ -149,8 +148,8 @@ public: return; } - /// Evaluates if coordinates are a portal going XP/XM; returns true if so, and writes boundaries to variable - /// Takes coordinates of base block and Y coord of target obsidian ceiling + /** Evaluates if coordinates are a portal going XP/XM; returns true if so, and writes boundaries to variable + Takes coordinates of base block and Y coord of target obsidian ceiling */ bool FindPortalSliceX(int X1, int X2, int Y, int Z, int MaxY, cChunkInterface & a_ChunkInterface) { Dir = 1; // Set assumed direction (will change if portal turns out to be facing the other direction) @@ -168,7 +167,8 @@ public: { return false; // Not valid slice, no portal can be formed } - } XZP = X1 - 1; // Set boundary of frame interior + } + XZP = X1 - 1; // Set boundary of frame interior for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM) { int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY); @@ -182,7 +182,9 @@ public: { return false; } - } XZM = X2 + 1; // Set boundary, see previous + } + XZM = X2 + 1; // Set boundary, see previous + return (FoundFrameXP && FoundFrameXM); } @@ -204,7 +206,8 @@ public: { return false; } - } XZP = Z1 - 1; + } + XZP = Z1 - 1; for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--) { int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY); @@ -218,7 +221,9 @@ public: { return false; } - } XZM = Z2 + 1; + } + XZM = Z2 + 1; + return (FoundFrameZP && FoundFrameZM); } }; diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index e8fd4c7f6..6f64c062b 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -19,7 +19,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } diff --git a/src/Blocks/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h index 6c198efc4..d1353e29a 100644 --- a/src/Blocks/BlockGlowstone.h +++ b/src/Blocks/BlockGlowstone.h @@ -15,13 +15,13 @@ public: : cBlockHandler(a_BlockType) { } - + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to 0 - MTRand r1; - a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, (char)(2 + r1.randInt(2)), 0)); + cFastRandom Random; + a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, (char)(2 + Random.NextInt(3)), 0)); } } ; diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 52f7dd608..028277e4c 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -45,13 +45,11 @@ #include "BlockLadder.h" #include "BlockLeaves.h" #include "BlockLilypad.h" -#include "BlockNewLeaves.h" #include "BlockLever.h" #include "BlockMelon.h" #include "BlockMushroom.h" #include "BlockMycelium.h" #include "BlockNetherWart.h" -#include "BlockNote.h" #include "BlockOre.h" #include "BlockPiston.h" #include "BlockPlanks.h" @@ -251,9 +249,9 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType); case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType); case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType); - case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType); + case E_BLOCK_NEW_LEAVES: return new cBlockLeavesHandler (a_BlockType); case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType); - case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType); + case E_BLOCK_NOTE_BLOCK: return new cBlockEntityHandler (a_BlockType); case E_BLOCK_PISTON: return new cBlockPistonHandler (a_BlockType); case E_BLOCK_PISTON_EXTENSION: return new cBlockPistonHeadHandler; case E_BLOCK_PLANKS: return new cBlockPlanksHandler (a_BlockType); diff --git a/src/Blocks/BlockMelon.h b/src/Blocks/BlockMelon.h index 2f7d9a461..60202d66e 100644 --- a/src/Blocks/BlockMelon.h +++ b/src/Blocks/BlockMelon.h @@ -19,8 +19,8 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - MTRand r1; - a_Pickups.push_back(cItem(E_ITEM_MELON_SLICE, (char)(3 + r1.randInt(4)), 0)); + cFastRandom Random; + a_Pickups.push_back(cItem(E_ITEM_MELON_SLICE, (char)(3 + Random.NextInt(5)), 0)); } diff --git a/src/Blocks/BlockNewLeaves.h b/src/Blocks/BlockNewLeaves.h deleted file mode 100644 index 5a267e8c6..000000000 --- a/src/Blocks/BlockNewLeaves.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "BlockHandler.h" -#include "BlockLeaves.h" -#include "../World.h" - - - - - - -class cBlockNewLeavesHandler : - public cBlockLeavesHandler -{ -public: - cBlockNewLeavesHandler(BLOCKTYPE a_BlockType) - : cBlockLeavesHandler(a_BlockType) - { - } - - - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - MTRand rand; - - // Only the first 2 bits contain the display information, the others are for growing - if (rand.randInt(5) == 0) - { - a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, (a_BlockMeta & 3) + 4)); - } - } - - - void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - } -} ; - - - - - diff --git a/src/Blocks/BlockNote.h b/src/Blocks/BlockNote.h deleted file mode 100644 index fef38d845..000000000 --- a/src/Blocks/BlockNote.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "BlockHandler.h" -#include "BlockEntity.h" - -class cBlockNoteHandler : public cBlockEntityHandler -{ -public: - cBlockNoteHandler(BLOCKTYPE a_BlockType) - : cBlockEntityHandler(a_BlockType) - { - } - -}; diff --git a/src/Blocks/BlockOre.h b/src/Blocks/BlockOre.h index 9684dbb19..0067d475f 100644 --- a/src/Blocks/BlockOre.h +++ b/src/Blocks/BlockOre.h @@ -2,7 +2,6 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" #include "../World.h" @@ -20,58 +19,41 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - short ItemType = m_BlockType; - char Count = 1; - short Meta = 0; - - MTRand r1; + cFastRandom Random; + switch (m_BlockType) { case E_BLOCK_LAPIS_ORE: { - ItemType = E_ITEM_DYE; - Count = 4 + (char)r1.randInt(4); - Meta = 4; + a_Pickups.push_back(cItem(E_ITEM_DYE, (char)(4 + Random.NextInt(5)), 4)); break; } case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: { - Count = 4 + (char)r1.randInt(1); + a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, (char)(4 + Random.NextInt(2)), 0)); break; } - default: - { - Count = 1; - break; - } - } - - switch (m_BlockType) - { case E_BLOCK_DIAMOND_ORE: { - ItemType = E_ITEM_DIAMOND; - break; - } - case E_BLOCK_REDSTONE_ORE: - case E_BLOCK_REDSTONE_ORE_GLOWING: - { - ItemType = E_ITEM_REDSTONE_DUST; + a_Pickups.push_back(cItem(E_ITEM_DIAMOND)); break; } case E_BLOCK_EMERALD_ORE: { - ItemType = E_ITEM_EMERALD; + a_Pickups.push_back(cItem(E_ITEM_EMERALD)); break; } case E_BLOCK_COAL_ORE: { - ItemType = E_ITEM_COAL; + a_Pickups.push_back(cItem(E_ITEM_COAL)); break; } + default: + { + ASSERT(!"Unhandled ore!"); + } } - a_Pickups.push_back(cItem(ItemType, Count, Meta)); } } ; diff --git a/src/Blocks/BlockPlanks.h b/src/Blocks/BlockPlanks.h index de84ed319..4c5bb4860 100644 --- a/src/Blocks/BlockPlanks.h +++ b/src/Blocks/BlockPlanks.h @@ -24,8 +24,7 @@ public: ) override { a_BlockType = m_BlockType; - NIBBLETYPE Meta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage); - a_BlockMeta = Meta; + a_BlockMeta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage); return true; } diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index fc74e89d0..8fac2a126 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -36,7 +36,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - return; // No pickups + // No pickups } virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override @@ -47,15 +47,15 @@ public: return; } - int PosX = a_Chunk.GetPosX() * 16 + a_RelX; - int PosZ = a_Chunk.GetPosZ() * 16 + a_RelZ; + int PosX = a_Chunk.GetPosX() * cChunkDef::Width + a_RelX; + int PosZ = a_Chunk.GetPosZ() * cChunkDef::Width + a_RelZ; a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, cMonster::mtZombiePigman); } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - if ((a_RelY - 1 < 0) || (a_RelY + 1 > cChunkDef::Height)) + if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height)) { return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 } diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index adec36eb6..a5c34a776 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -17,7 +17,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } @@ -29,7 +29,7 @@ public: } BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); - return ((BlockBelow == E_BLOCK_FENCE_GATE) || (BlockBelow == E_BLOCK_FENCE) || cBlockInfo::IsSolid(BlockBelow)); + return (cBlockInfo::IsSolid(BlockBelow)); } } ; diff --git a/src/Blocks/BlockQuartz.h b/src/Blocks/BlockQuartz.h index 2ce7e71e4..edc4fb9c5 100644 --- a/src/Blocks/BlockQuartz.h +++ b/src/Blocks/BlockQuartz.h @@ -25,6 +25,7 @@ public: { a_BlockType = m_BlockType; NIBBLETYPE Meta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage); + if (Meta != E_META_QUARTZ_PILLAR) // Check if the block is a pillar block. { a_BlockMeta = Meta; diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index a898c9acb..37d61ed73 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -26,8 +26,8 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 - a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1)); + // Reset meta to zero + a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1, 0)); } } ; diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 4c8a6a087..4b18add12 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -23,7 +23,7 @@ public: int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + ) override { a_BlockType = m_BlockType; a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw()); @@ -46,7 +46,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(E_ITEM_REDSTONE_REPEATER, 1, 0)); } @@ -59,7 +59,7 @@ public: virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); + return ((a_RelY > 0) && cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))); } diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index a7ccf1714..417969a82 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -16,8 +16,8 @@ public: { } - - + + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -53,8 +53,8 @@ public: } return true; } - - + + virtual const char * GetStepSound(void) override { if ( @@ -64,7 +64,7 @@ public: (m_BlockType == E_BLOCK_ACACIA_WOOD_STAIRS) || (m_BlockType == E_BLOCK_BIRCH_WOOD_STAIRS) || (m_BlockType == E_BLOCK_DARK_OAK_WOOD_STAIRS) - ) + ) { return "step.wood"; } @@ -72,17 +72,20 @@ public: return "step.stone"; } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override { return true; } - + + static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 90 + 45; // So its not aligned with axis @@ -108,14 +111,11 @@ public: } } - virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override { // Toggle bit 3: return (a_Meta & 0x0b) | ((~a_Meta) & 0x04); } - - } ; diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index 84d3b2e7d..5902c791b 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -29,6 +29,7 @@ public: { return false; } + switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)) { case E_BLOCK_DIRT: diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index c73118870..df5574d5d 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -126,7 +126,7 @@ public: (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL)) && (Face == BLOCK_FACE_TOP) - ) + ) { return Face; } @@ -162,7 +162,7 @@ public: (BlockInQuestion == E_BLOCK_END_PORTAL_FRAME) || // Actual vanilla behaviour (BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE) || (BlockInQuestion == E_BLOCK_COBBLESTONE_WALL) - ) + ) { // Torches can be placed on tops of glass and fences, despite them being 'untorcheable' // No need to check for upright orientation, it was done when the torch was placed diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 6a36ab874..a6327b5c2 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -23,7 +23,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } @@ -53,7 +53,7 @@ public: int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + ) override { a_BlockType = m_BlockType; a_BlockMeta = BlockFaceToMetaData(a_BlockFace); @@ -103,9 +103,10 @@ public: a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); - BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); + BLOCKTYPE BlockIsOn; + a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); - return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn); + return ((a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn)); } }; diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index f849fb8ad..4f9d79483 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -21,10 +21,9 @@ public: int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + ) override { a_BlockType = m_BlockType; - a_BlockMeta = DirectionToMetadata(a_BlockFace); return true; @@ -56,7 +55,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(E_BLOCK_TRIPWIRE_HOOK, 1, 0)); } @@ -66,9 +65,10 @@ public: a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta); AddFaceDirection(a_RelX, a_RelY, a_RelZ, MetadataToDirection(Meta), true); - BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); + BLOCKTYPE BlockIsOn; + a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); - return (a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn); + return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn)); } virtual const char * GetStepSound(void) override diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 1e1f6d8d2..578224c61 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -46,7 +46,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - // Reset meta to 0 + // Reset meta to zero a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0)); } @@ -80,7 +80,7 @@ public: /// Returns true if the specified block type is good for vines to attach to static bool IsBlockAttachable(BLOCKTYPE a_BlockType) { - return (a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType); + return ((a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType)); } @@ -182,7 +182,7 @@ public: a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block); if (Block == E_BLOCK_AIR) { - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX * cChunkDef::Width, a_RelY - 1, a_RelZ * cChunkDef::Width, ssVineSpread)) + if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread)) { a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); } diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 7bdf4196d..116c0f3a0 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #ifndef _WIN32 diff --git a/src/Items/ItemGoldenApple.h b/src/Items/ItemGoldenApple.h index 4e1096e65..02ac0202c 100644 --- a/src/Items/ItemGoldenApple.h +++ b/src/Items/ItemGoldenApple.h @@ -29,7 +29,7 @@ public: a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 100, 1); // When the apple is a 'notch apple', give extra effects: - if (a_Item->m_ItemDamage > 0) + if (a_Item->m_ItemDamage >= E_META_GOLDEN_APPLE_ENCHANTED) { a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 600, 4); a_Player->AddEntityEffect(cEntityEffect::effResistance, 6000, 0); diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h index 7d5760fa9..cd235678d 100644 --- a/src/Items/ItemShovel.h +++ b/src/Items/ItemShovel.h @@ -19,7 +19,6 @@ public: cItemShovelHandler(int a_ItemType) : cItemHandler(a_ItemType) { - } virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override diff --git a/src/World.cpp b/src/World.cpp index b357b8a23..2027e215a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "BlockID.h" From 67fc19301e4909101c6f2f31cb5d49413fe47d42 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 12:14:56 +0200 Subject: [PATCH 203/751] Removed old classes from the CMakeLists.txt --- src/Blocks/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 05b7bfab4..9f971a8bd 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -57,8 +57,6 @@ SET (HDRS BlockMushroom.h BlockMycelium.h BlockNetherWart.h - BlockNewLeaves.h - BlockNote.h BlockOre.h BlockPiston.h BlockPlanks.h From 228dd61995a404b6c59832bf8b0f8375374c8acc Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 16:01:30 +0200 Subject: [PATCH 204/751] Added HOOK_SERVER_PING --- src/Bindings/LuaState_Call.inc | 847 ++++++++++++++++++++++++++++++ src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 4 +- src/Bindings/PluginLua.h | 2 +- src/Bindings/PluginManager.cpp | 4 +- src/Bindings/PluginManager.h | 2 +- src/Protocol/Protocol17x.cpp | 99 +++- src/Protocol/ProtocolRecognizer.h | 2 +- 8 files changed, 926 insertions(+), 36 deletions(-) create mode 100644 src/Bindings/LuaState_Call.inc diff --git a/src/Bindings/LuaState_Call.inc b/src/Bindings/LuaState_Call.inc new file mode 100644 index 000000000..810b0551b --- /dev/null +++ b/src/Bindings/LuaState_Call.inc @@ -0,0 +1,847 @@ +// LuaState_Call.inc + +// This file is auto-generated by gen_LuaState_Call.lua +// Make changes to the generator instead of to this file! + +// This file contains the various overloads for the cLuaState::Call() function +// Each overload handles a different number of parameters / return values + + + + + +/** Call the specified 0-param 0-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function) +{ + if (!PushFunction(a_Function)) + { + return false; + } + if (!CallFunction(0)) + { + return false; + } + return true; +} + + + + + +/** Call the specified 1-param 0-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1) +{ + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + if (!CallFunction(0)) + { + return false; + } + return true; +} + + + + + +/** Call the specified 2-param 0-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2) +{ + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + if (!CallFunction(0)) + { + return false; + } + return true; +} + + + + + +/** Call the specified 3-param 0-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3) +{ + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + if (!CallFunction(0)) + { + return false; + } + return true; +} + + + + + +/** Call the specified 4-param 0-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4) +{ + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + if (!CallFunction(0)) + { + return false; + } + return true; +} + + + + + +/** Call the specified 0-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 1-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 2-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 3-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 4-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 5-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 6-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 7-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 8-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 9-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + Push(a_Param9); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 10-param 1-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, ParamT10 a_Param10, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + Push(a_Param9); + Push(a_Param10); + if (!CallFunction(1)) + { + return false; + } + GetStackValue(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; +} + + + + + +/** Call the specified 0-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 1-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 2-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 3-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 4-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 5-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 6-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 7-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 8-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 9-param 2-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + Push(a_Param9); + if (!CallFunction(2)) + { + return false; + } + GetStackValue(-2, a_Ret1); + GetStackValue(-1, a_Ret2); + lua_pop(m_LuaState, 2); + return true; +} + + + + + +/** Call the specified 7-param 3-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + if (!CallFunction(3)) + { + return false; + } + GetStackValue(-3, a_Ret1); + GetStackValue(-2, a_Ret2); + GetStackValue(-1, a_Ret3); + lua_pop(m_LuaState, 3); + return true; +} + + + + + +/** Call the specified 8-param 3-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + if (!CallFunction(3)) + { + return false; + } + GetStackValue(-3, a_Ret1); + GetStackValue(-2, a_Ret2); + GetStackValue(-1, a_Ret3); + lua_pop(m_LuaState, 3); + return true; +} + + + + + +/** Call the specified 4-param 5-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3, RetT4 & a_Ret4, RetT5 & a_Ret5) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + if (!CallFunction(5)) + { + return false; + } + GetStackValue(-5, a_Ret1); + GetStackValue(-4, a_Ret2); + GetStackValue(-3, a_Ret3); + GetStackValue(-2, a_Ret4); + GetStackValue(-1, a_Ret5); + lua_pop(m_LuaState, 5); + return true; +} + + + + + +/** Call the specified 9-param 5-return Lua function: +Returns true if call succeeded, false if there was an error. */ +template +bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3, RetT4 & a_Ret4, RetT5 & a_Ret5) +{ + UNUSED(a_RetMark); + if (!PushFunction(a_Function)) + { + return false; + } + Push(a_Param1); + Push(a_Param2); + Push(a_Param3); + Push(a_Param4); + Push(a_Param5); + Push(a_Param6); + Push(a_Param7); + Push(a_Param8); + Push(a_Param9); + if (!CallFunction(5)) + { + return false; + } + GetStackValue(-5, a_Ret1); + GetStackValue(-4, a_Ret2); + GetStackValue(-3, a_Ret3); + GetStackValue(-2, a_Ret4); + GetStackValue(-1, a_Ret5); + lua_pop(m_LuaState, 5); + return true; +} + + + + + diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 6f05af51b..fef86822d 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -91,7 +91,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) = 0; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; - virtual bool OnServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; + virtual bool OnServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 066e050d6..dbe2e7a0d 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1193,14 +1193,14 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity -bool cPluginLua::OnServerPing(const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginLua::OnServerPing(AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Username, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); + m_LuaState.Call((int)(**itr), a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); if (res) { return true; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 2d98477f0..185b2a887 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -117,7 +117,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) override; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; - virtual bool OnServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; + virtual bool OnServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index b9d28205d..fcbb446c1 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1189,14 +1189,14 @@ bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectil -bool cPluginManager::CallHookServerPing(const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginManager::CallHookServerPing(AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { FIND_HOOK(HOOK_SERVER_PING); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnServerPing(a_Username, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) + if ((*itr)->OnServerPing(a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) { return true; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 104e4c7a9..db8a2ca64 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -226,7 +226,7 @@ public: bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos); bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); - bool CallHookServerPing (const AString & a_Username, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); + bool CallHookServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 1f8ca00bb..31a140c73 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -41,6 +41,8 @@ Implements the 1.7.x protocol classes: #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" +#include "Bindings/PluginManager.h" +#include "lua/src/llex.h" @@ -1715,21 +1717,41 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { - // Send the response: - AString Response = "{\"version\":{\"name\":\"1.7.2\", \"protocol\":4}, \"players\":{"; cServer * Server = cRoot::Get()->GetServer(); - AppendPrintf(Response, "\"max\":%u, \"online\":%u, \"sample\":[]},", - Server->GetMaxPlayers(), - Server->GetNumPlayers() - ); - AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", - Server->GetDescription().c_str() - ); - AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"", - Server->GetFaviconData().c_str() - ); - Response.append("}"); - + AString Motd = Server->GetDescription(); + int NumPlayers = Server->GetNumPlayers(); + int MaxPlayers = Server->GetMaxPlayers(); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(Motd, NumPlayers, MaxPlayers, Favicon); + + // Version: + Json::Value Version; + Version["name"] = "1.7.2"; + Version["protocol"] = 4; + + // Players: + Json::Value Players; + Players["online"] = NumPlayers; + Players["max"] = MaxPlayers; + // TODO: Add "sample" + + // Description: + Json::Value Description; + Description["text"] = Motd.c_str(); + + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + if (!Favicon.empty()) + { + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); + } + + Json::StyledWriter Writer; + AString Response = Writer.write(ResponseValue); + cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Response); } @@ -3065,20 +3087,41 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { - // Send the response: - AString Response = "{\"version\": {\"name\": \"1.7.6\", \"protocol\":5}, \"players\": {"; - AppendPrintf(Response, "\"max\": %u, \"online\": %u, \"sample\": []},", - cRoot::Get()->GetServer()->GetMaxPlayers(), - cRoot::Get()->GetServer()->GetNumPlayers() - ); - AppendPrintf(Response, "\"description\": {\"text\": \"%s\"},", - cRoot::Get()->GetServer()->GetDescription().c_str() - ); - AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"", - cRoot::Get()->GetServer()->GetFaviconData().c_str() - ); - Response.append("}"); - + cServer * Server = cRoot::Get()->GetServer(); + AString Motd = Server->GetDescription(); + int NumPlayers = Server->GetNumPlayers(); + int MaxPlayers = Server->GetMaxPlayers(); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(Motd, NumPlayers, MaxPlayers, Favicon); + + // Version: + Json::Value Version; + Version["name"] = "1.7.6"; + Version["protocol"] = 5; + + // Players: + Json::Value Players; + Players["online"] = NumPlayers; + Players["max"] = MaxPlayers; + // TODO: Add "sample" + + // Description: + Json::Value Description; + Description["text"] = Motd.c_str(); + + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + if (!Favicon.empty()) + { + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); + } + + Json::StyledWriter Writer; + AString Response = Writer.write(ResponseValue); + cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Response); } diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 65829ef73..796464202 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,7 +18,7 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9" +#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10" #define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5" From 2cca4d70c8b3908bcd692fffb937c0fa6b5b29a3 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 16:04:18 +0200 Subject: [PATCH 205/751] Cleaned up code. --- src/Bindings/LuaState_Call.inc | 847 ----------------------------- src/Bindings/gen_LuaState_Call.lua | 1 + src/Protocol/Protocol17x.cpp | 1 - 3 files changed, 1 insertion(+), 848 deletions(-) delete mode 100644 src/Bindings/LuaState_Call.inc diff --git a/src/Bindings/LuaState_Call.inc b/src/Bindings/LuaState_Call.inc deleted file mode 100644 index 810b0551b..000000000 --- a/src/Bindings/LuaState_Call.inc +++ /dev/null @@ -1,847 +0,0 @@ -// LuaState_Call.inc - -// This file is auto-generated by gen_LuaState_Call.lua -// Make changes to the generator instead of to this file! - -// This file contains the various overloads for the cLuaState::Call() function -// Each overload handles a different number of parameters / return values - - - - - -/** Call the specified 0-param 0-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function) -{ - if (!PushFunction(a_Function)) - { - return false; - } - if (!CallFunction(0)) - { - return false; - } - return true; -} - - - - - -/** Call the specified 1-param 0-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1) -{ - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - if (!CallFunction(0)) - { - return false; - } - return true; -} - - - - - -/** Call the specified 2-param 0-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2) -{ - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - if (!CallFunction(0)) - { - return false; - } - return true; -} - - - - - -/** Call the specified 3-param 0-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3) -{ - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - if (!CallFunction(0)) - { - return false; - } - return true; -} - - - - - -/** Call the specified 4-param 0-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4) -{ - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - if (!CallFunction(0)) - { - return false; - } - return true; -} - - - - - -/** Call the specified 0-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 1-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 2-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 3-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 4-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 5-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 6-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 7-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 8-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 9-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - Push(a_Param9); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 10-param 1-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, ParamT10 a_Param10, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - Push(a_Param9); - Push(a_Param10); - if (!CallFunction(1)) - { - return false; - } - GetStackValue(-1, a_Ret1); - lua_pop(m_LuaState, 1); - return true; -} - - - - - -/** Call the specified 0-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 1-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 2-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 3-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 4-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 5-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 6-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 7-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 8-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 9-param 2-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - Push(a_Param9); - if (!CallFunction(2)) - { - return false; - } - GetStackValue(-2, a_Ret1); - GetStackValue(-1, a_Ret2); - lua_pop(m_LuaState, 2); - return true; -} - - - - - -/** Call the specified 7-param 3-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - if (!CallFunction(3)) - { - return false; - } - GetStackValue(-3, a_Ret1); - GetStackValue(-2, a_Ret2); - GetStackValue(-1, a_Ret3); - lua_pop(m_LuaState, 3); - return true; -} - - - - - -/** Call the specified 8-param 3-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - if (!CallFunction(3)) - { - return false; - } - GetStackValue(-3, a_Ret1); - GetStackValue(-2, a_Ret2); - GetStackValue(-1, a_Ret3); - lua_pop(m_LuaState, 3); - return true; -} - - - - - -/** Call the specified 4-param 5-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3, RetT4 & a_Ret4, RetT5 & a_Ret5) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - if (!CallFunction(5)) - { - return false; - } - GetStackValue(-5, a_Ret1); - GetStackValue(-4, a_Ret2); - GetStackValue(-3, a_Ret3); - GetStackValue(-2, a_Ret4); - GetStackValue(-1, a_Ret5); - lua_pop(m_LuaState, 5); - return true; -} - - - - - -/** Call the specified 9-param 5-return Lua function: -Returns true if call succeeded, false if there was an error. */ -template -bool Call(FnT a_Function, ParamT1 a_Param1, ParamT2 a_Param2, ParamT3 a_Param3, ParamT4 a_Param4, ParamT5 a_Param5, ParamT6 a_Param6, ParamT7 a_Param7, ParamT8 a_Param8, ParamT9 a_Param9, const cLuaState::cRet & a_RetMark, RetT1 & a_Ret1, RetT2 & a_Ret2, RetT3 & a_Ret3, RetT4 & a_Ret4, RetT5 & a_Ret5) -{ - UNUSED(a_RetMark); - if (!PushFunction(a_Function)) - { - return false; - } - Push(a_Param1); - Push(a_Param2); - Push(a_Param3); - Push(a_Param4); - Push(a_Param5); - Push(a_Param6); - Push(a_Param7); - Push(a_Param8); - Push(a_Param9); - if (!CallFunction(5)) - { - return false; - } - GetStackValue(-5, a_Ret1); - GetStackValue(-4, a_Ret2); - GetStackValue(-3, a_Ret3); - GetStackValue(-2, a_Ret4); - GetStackValue(-1, a_Ret5); - lua_pop(m_LuaState, 5); - return true; -} - - - - - diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index 17bae82b3..41b3e3068 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -56,6 +56,7 @@ local Combinations = -- Special combinations: {7, 3}, {8, 3}, + {4, 5}, {9, 5}, } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 31a140c73..0a9d70bcc 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -42,7 +42,6 @@ Implements the 1.7.x protocol classes: #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" #include "Bindings/PluginManager.h" -#include "lua/src/llex.h" From cfdf39a75f68c902e78f78bf3396ce94104903b5 Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 16:12:05 +0200 Subject: [PATCH 206/751] Added "HOOK_SERVER_PING" call to older protocols --- src/Protocol/ProtocolRecognizer.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index a7fb7bcc2..b197cd384 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -1013,6 +1013,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) { AString Reply; cServer * Server = cRoot::Get()->GetServer(); + + AString Motd = Server->GetDescription(); + int NumPlayers = Server->GetNumPlayers(); + int MaxPlayers = Server->GetMaxPlayers(); + switch (cRoot::Get()->GetPrimaryServerVersion()) { case PROTO_VERSION_1_2_5: @@ -1020,11 +1025,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) { // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29 Printf(Reply, "%s%s%i%s%i", - Server->GetDescription().c_str(), + Motd.c_str(), cChatColor::Delimiter, - Server->GetNumPlayers(), + NumPlayers, cChatColor::Delimiter, - Server->GetMaxPlayers() + MaxPlayers ); break; } @@ -1051,13 +1056,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) m_Buffer.ReadByte(val); // 0x01 magic value ASSERT(val == 0x01); } - - // http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100 - AString NumPlayers; - Printf(NumPlayers, "%d", Server->GetNumPlayers()); - AString MaxPlayers; - Printf(MaxPlayers, "%d", Server->GetMaxPlayers()); - + AString ProtocolVersionNum; Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion()); AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->GetPrimaryServerVersion())); @@ -1070,11 +1069,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) Reply.push_back(0); Reply.append(ProtocolVersionTxt); Reply.push_back(0); - Reply.append(Server->GetDescription()); + Reply.append(Motd); Reply.push_back(0); - Reply.append(NumPlayers); + Reply.append(Printf("%d", NumPlayers)); Reply.push_back(0); - Reply.append(MaxPlayers); + Reply.append(Printf("%d", MaxPlayers)); break; } } // switch (m_PrimaryServerVersion) From 81979419ad175c98d462ef58cdd39c7c609cd7c5 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 17:56:30 +0200 Subject: [PATCH 207/751] 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 208/751] 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 209/751] 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 210/751] 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 cf5ab14ca59904e208bf6cb9d87134f01803eeed Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 22:19:50 +0200 Subject: [PATCH 211/751] Added a_ClientHandle to the HOOK_SERVER_PING hook. --- src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 5 +++-- src/Bindings/PluginLua.h | 2 +- src/Bindings/PluginManager.cpp | 4 ++-- src/Bindings/PluginManager.h | 2 +- src/Bindings/gen_LuaState_Call.lua | 2 +- src/Protocol/Protocol17x.cpp | 4 ++-- src/Protocol/ProtocolRecognizer.cpp | 3 +++ 8 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index fef86822d..16d789598 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -91,7 +91,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) = 0; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; - virtual bool OnServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; + virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index dbe2e7a0d..343164ec7 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1193,14 +1193,14 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity -bool cPluginLua::OnServerPing(AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); + m_LuaState.Call((int)(**itr), &a_ClientHandle, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); if (res) { return true; @@ -1590,6 +1590,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_PLUGINS_LOADED: return "OnPluginsLoaded"; case cPluginManager::HOOK_POST_CRAFTING: return "OnPostCrafting"; case cPluginManager::HOOK_PRE_CRAFTING: return "OnPreCrafting"; + case cPluginManager::HOOK_SERVER_PING: return "OnServerPing"; case cPluginManager::HOOK_SPAWNED_ENTITY: return "OnSpawnedEntity"; case cPluginManager::HOOK_SPAWNED_MONSTER: return "OnSpawnedMonster"; case cPluginManager::HOOK_SPAWNING_ENTITY: return "OnSpawningEntity"; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 185b2a887..549045849 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -117,7 +117,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) override; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; - virtual bool OnServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; + virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index fcbb446c1..2ce46e8fe 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1189,14 +1189,14 @@ bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectil -bool cPluginManager::CallHookServerPing(AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginManager::CallHookServerPing(cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { FIND_HOOK(HOOK_SERVER_PING); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnServerPing(a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) + if ((*itr)->OnServerPing(a_ClientHandle, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) { return true; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index db8a2ca64..ac46fc077 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -226,7 +226,7 @@ public: bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos); bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); - bool CallHookServerPing (AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); + bool CallHookServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); diff --git a/src/Bindings/gen_LuaState_Call.lua b/src/Bindings/gen_LuaState_Call.lua index 41b3e3068..c1d1af771 100644 --- a/src/Bindings/gen_LuaState_Call.lua +++ b/src/Bindings/gen_LuaState_Call.lua @@ -56,7 +56,7 @@ local Combinations = -- Special combinations: {7, 3}, {8, 3}, - {4, 5}, + {5, 5}, {9, 5}, } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 0a9d70bcc..565532913 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1721,7 +1721,7 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); - cRoot::Get()->GetPluginManager()->CallHookServerPing(Motd, NumPlayers, MaxPlayers, Favicon); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; @@ -3091,7 +3091,7 @@ void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); - cRoot::Get()->GetPluginManager()->CallHookServerPing(Motd, NumPlayers, MaxPlayers, Favicon); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index b197cd384..af5a8a416 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -18,6 +18,7 @@ #include "../Server.h" #include "../World.h" #include "../ChatColor.h" +#include "Bindings/PluginManager.h" @@ -1017,6 +1018,8 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) AString Motd = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon); switch (cRoot::Get()->GetPrimaryServerVersion()) { From 2218f31cde5d04157469de0d5164059ffb8a6bca Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 22:21:41 +0200 Subject: [PATCH 212/751] 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 4da61e67d7638c46dc56fe451e81a5b4b0f134db Mon Sep 17 00:00:00 2001 From: Howaner Date: Wed, 20 Aug 2014 22:22:38 +0200 Subject: [PATCH 213/751] Renamed a_Motd to a_ServerDescription. --- src/Bindings/Plugin.h | 2 +- src/Bindings/PluginLua.cpp | 4 ++-- src/Bindings/PluginLua.h | 2 +- src/Bindings/PluginManager.cpp | 4 ++-- src/Bindings/PluginManager.h | 2 +- src/Protocol/Protocol17x.cpp | 6 +++--- src/Protocol/ProtocolRecognizer.cpp | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 16d789598..b4dfeb8cf 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -91,7 +91,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) = 0; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0; - virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; + virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 343164ec7..462dda629 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1193,14 +1193,14 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity -bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), &a_ClientHandle, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); + m_LuaState.Call((int)(**itr), &a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon); if (res) { return true; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 549045849..d3b0d2723 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -117,7 +117,7 @@ public: virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) override; virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override; - virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; + virtual bool OnServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 2ce46e8fe..f708c2d85 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -1189,14 +1189,14 @@ bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectil -bool cPluginManager::CallHookServerPing(cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) +bool cPluginManager::CallHookServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { FIND_HOOK(HOOK_SERVER_PING); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnServerPing(a_ClientHandle, a_Motd, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) + if ((*itr)->OnServerPing(a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon)) { return true; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index ac46fc077..a60a0cdda 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -226,7 +226,7 @@ public: bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos); bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity); - bool CallHookServerPing (cClientHandle & a_ClientHandle, AString & a_Motd, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); + bool CallHookServerPing (cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 565532913..59db0b7d8 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1717,11 +1717,11 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { cServer * Server = cRoot::Get()->GetServer(); - AString Motd = Server->GetDescription(); + AString ServerDescription = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); - cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; @@ -1736,7 +1736,7 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) // Description: Json::Value Description; - Description["text"] = Motd.c_str(); + Description["text"] = ServerDescription.c_str(); // Create the response: Json::Value ResponseValue; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index af5a8a416..6e6cb3caf 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -1015,11 +1015,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) AString Reply; cServer * Server = cRoot::Get()->GetServer(); - AString Motd = Server->GetDescription(); + AString ServerDescription = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); - cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); switch (cRoot::Get()->GetPrimaryServerVersion()) { @@ -1028,7 +1028,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) { // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29 Printf(Reply, "%s%s%i%s%i", - Motd.c_str(), + ServerDescription.c_str(), cChatColor::Delimiter, NumPlayers, cChatColor::Delimiter, @@ -1072,7 +1072,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) Reply.push_back(0); Reply.append(ProtocolVersionTxt); Reply.push_back(0); - Reply.append(Motd); + Reply.append(ServerDescription); Reply.push_back(0); Reply.append(Printf("%d", NumPlayers)); Reply.push_back(0); From b7ec75add6c0904b3950ce13ebe16888fd237c05 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 20 Aug 2014 22:27:58 +0200 Subject: [PATCH 214/751] 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 19d1c976e7cd7f6c8a4cb3540d5512a035a4162a Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Thu, 21 Aug 2014 12:08:38 +0200 Subject: [PATCH 215/751] Protection Enchantments, some fixes - Protection echantments (fire, blast, feather falling, protection and projectile). It isn't finished, add secondary effects and optimize the code. - Removed some brackets. - Silk touch fixed. --- src/Blocks/BlockHandler.cpp | 15 ++--- src/Entities/ArrowEntity.cpp | 10 ++-- src/Entities/Entity.cpp | 110 ++++++++++++++++++++++++++++++++++- src/Entities/Player.cpp | 2 +- 4 files changed, 122 insertions(+), 15 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 2238a68a0..0155aa97b 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -428,8 +428,14 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac { if (!a_DropVerbatim) { + ConvertToPickups(Pickups, Meta); + } + else + { + // TODO: Add a proper overridable function for this + // Pickups.Add(m_BlockType, 1, Meta); cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments; - if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && (a_Digger->IsPlayer())) + if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer()) { switch (m_BlockType) { @@ -459,14 +465,9 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac } else { - ConvertToPickups(Pickups, Meta); + Pickups.Add(m_BlockType, 1, Meta); } } - else - { - // TODO: Add a proper overridable function for this - Pickups.Add(m_BlockType, 1, Meta); - } } // Allow plugins to modify the pickups: diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 12149b297..c3e7c5d79 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -91,7 +91,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa // Broadcast arrow hit sound m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && (IsOnFire())) + if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && IsOnFire()) { m_World->SetBlock(X, Y, Z, E_BLOCK_AIR, 0); m_World->SpawnPrimedTNT(X, Y, Z); @@ -122,12 +122,12 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) int PunchLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPunch); if (PunchLevel > 0) { - Vector3f LookVector = Vector3d(0, 0, 0); + Vector3d LookVector = GetLookVector(); Vector3f FinalSpeed = Vector3f(0, 0, 0); switch (PunchLevel) { - case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); - case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); + case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); break; + case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); break; default: break; } a_EntityHit.SetSpeed(FinalSpeed); @@ -135,7 +135,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); - if ((IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())) + if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming()) { a_EntityHit.StartBurning(100); } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 54e4cf4f5..a4c5c4b2a 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -13,6 +13,7 @@ #include "../Tracer.h" #include "Player.h" #include "Items/ItemHandler.h" +#include "../FastRandom.h" @@ -324,7 +325,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) if (SharpnessLevel > 0) { - a_TDI.RawDamage += 1.25 * SharpnessLevel; + a_TDI.FinalDamage += 1.25 * SharpnessLevel; } else if (SmiteLevel > 0) { @@ -338,7 +339,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case cMonster::mtWither: case cMonster::mtZombiePigman: { - a_TDI.RawDamage += 2.5 * SmiteLevel; + a_TDI.FinalDamage += 2.5 * SmiteLevel; break; } } @@ -404,6 +405,110 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); } + if (IsPlayer()){ + double TotalEPF = 0.0; + double EPFProtection = 0.00; + double EPFFireProtection = 0.00; + double EPFBlastProtection = 0.00; + double EPFProjectileProtection = 0.00; + double EPFFeatherFalling = 0.00; + + cEnchantments ChestplateEnchantments = GetEquippedChestplate().m_Enchantments; + cEnchantments LeggingsEnchantments = GetEquippedLeggings().m_Enchantments; + cEnchantments BootsEnchantments = GetEquippedBoots().m_Enchantments; + cEnchantments HelmetEnchantments = GetEquippedHelmet().m_Enchantments; + + if ((ChestplateEnchantments.GetLevel(cEnchantments::enchProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchProtection) > 0) + || (BootsEnchantments.GetLevel(cEnchantments::enchProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchProtection) > 0)) + { + EPFProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + EPFProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + EPFProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + EPFProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + + TotalEPF += EPFProtection; + } + + if ((ChestplateEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) + || (BootsEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0)) + { + EPFFireProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; + EPFFireProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; + EPFFireProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; + EPFFireProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; + + TotalEPF += EPFFireProtection; + } + + if ((ChestplateEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) + || (BootsEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0)) + { + EPFFeatherFalling += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; + EPFFeatherFalling += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; + EPFFeatherFalling += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; + EPFFeatherFalling += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; + + TotalEPF += EPFFeatherFalling; + } + + if ((ChestplateEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) + || (BootsEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0)) + { + EPFBlastProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; + EPFBlastProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; + EPFBlastProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; + EPFBlastProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; + + TotalEPF += EPFBlastProtection; + } + + if ((ChestplateEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) + || (BootsEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0)) + { + EPFProjectileProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; + EPFProjectileProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; + EPFProjectileProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; + EPFProjectileProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; + + TotalEPF += EPFProjectileProtection; + } + + EPFProtection = EPFProtection / TotalEPF; + EPFFireProtection = EPFFireProtection / TotalEPF; + EPFFeatherFalling = EPFFeatherFalling / TotalEPF; + EPFBlastProtection = EPFBlastProtection / TotalEPF; + EPFProjectileProtection = EPFProjectileProtection / TotalEPF; + + if (TotalEPF > 25) TotalEPF = 25; + + cFastRandom Random; + float randomvalue; + randomvalue = Random.GenerateRandomInteger(50, 100) * 0.01; + + TotalEPF = ceil(TotalEPF * randomvalue); + + if (TotalEPF > 20) TotalEPF = 20; + + EPFProtection = TotalEPF * EPFProtection; + EPFFireProtection = TotalEPF * EPFFireProtection; + EPFFeatherFalling = TotalEPF * EPFFeatherFalling; + EPFBlastProtection = TotalEPF * EPFBlastProtection; + EPFProjectileProtection = TotalEPF * EPFProjectileProtection; + + int RemovedDamage = 0; + + if (a_TDI.DamageType != dtInVoid) RemovedDamage += ceil(EPFProtection * 0.04 * a_TDI.FinalDamage); + + if ((a_TDI.DamageType == dtFalling) || (a_TDI.DamageType == dtFall) || (a_TDI.DamageType == dtEnderPearl)) RemovedDamage += ceil(EPFFeatherFalling * 0.04 * a_TDI.FinalDamage); + + if (a_TDI.DamageType == dtBurning) RemovedDamage += ceil(EPFFireProtection * 0.04 * a_TDI.FinalDamage); + + if (a_TDI.DamageType == dtExplosion) RemovedDamage += ceil(EPFBlastProtection * 0.04 * a_TDI.FinalDamage); + + if (a_TDI.DamageType == dtProjectile) RemovedDamage += ceil(EPFBlastProtection * 0.04 * a_TDI.FinalDamage); + + a_TDI.FinalDamage -= RemovedDamage; + } m_Health -= (short)a_TDI.FinalDamage; @@ -411,6 +516,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = std::max(m_Health, 0); + if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs { int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c1031907d..8b829d090 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1978,7 +1978,7 @@ void cPlayer::UseEquippedItem(int a_Amount) } cFastRandom Random; - if (Random.NextInt(100) <= chance) + if (Random.NextInt(101) <= chance) { return; } From 936604ca95d8e639a6783f9931093b689ce103d9 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 15:19:30 +0200 Subject: [PATCH 216/751] 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 217/751] 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 218/751] 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 219/751] 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 220/751] 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 221/751] 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 222/751] 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 223/751] 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 224/751] 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 f569826a95f8e405661a41e872eccd517fe1116a Mon Sep 17 00:00:00 2001 From: Masy98 Date: Thu, 21 Aug 2014 21:38:50 +0200 Subject: [PATCH 225/751] Added missing blocks in item.ini --- MCServer/items.ini | 51 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index 7b8fcf4ee..8f169157c 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -17,6 +17,11 @@ birchplanks=5:2 lightplanks=5:2 jungleplanks=5:3 redplanks=5:3 +acaciaplanks=5:4 +darkoakplanks=5:5 +bigoakplanks=5:5 +roofedoakplanks=5:5 + ; Obsolete: do not use "wood", as its meaning is not clear - wiki uses log as wood, we use planks as wood. wood=5 @@ -274,13 +279,47 @@ redstonelamp=123 redstonelampoff=123 redstonelampon=124 woodendoubleslab=125 +appledoublewood=125:0 +oakwooddoubleslab=125:0 +coniferwooddoubleslab=125:1 +pinewooddoubleslab=125:1 +sprucewooddoubleslab=125:1 +darkwooddoubleslab=125:1 +birchwooddoubleslab=125:2 +whitewooddoubleslab=125:2 +junglewooddoubleslab=125:3 +acaciawooddoubleslab=125:4 +bigoakwooddoubleslab=125:5 +darkoakwooddoubleslab=125:5 +roofedwooddoubleslab=125:5 woodenslab=126 +applewood=126:0 +oakwoodslab=126:0 +coniferwoodslab=126:1 +pinewoodslab=126:1 +sprucewoodslab=126:1 +darkwoodslab=126:1 +birchwoodslab=126:2 +whitewoodslab=126:2 +junglewoodslab=126:3 +acaciawoodslab=126:4 +bigoakwoodslab=126:5 +darkoakwoodslab=126:5 +roofedwoodslab=126:5 +cocoabeans=127 sandstonestairs=128 emeraldore=129 enderchest=130 tripwirehook=131 tripwire=132 emeraldblock=133 +coniferwoodstairs=134 +pinewoodstairs=134 +sprucewoodstairs=134 +darkwoodstairs=134 +birchwoodstairs=135 +whitewoodstairs=135 +junglewoodstairs=136 commandblock=137 beacon=138 cobblestonewall=139 @@ -343,10 +382,18 @@ brownstainedglasspane=160:12 greenstainedglasspane=160:13 redstainedglasspane=160:14 blackstainedglasspane=160:15 +acacialeaves=161 +bigoakleaves=161:1 +darkoakleaves=161:1 +roofedoakleaves=161:1 acaciawood=162 +bigoakwood=162:1 darkoakwood=162:1 -acaciawoodenstairs=163 -darkoakwoodenstairs=164 +roofedoakwood=162:1 +acaciawoodstairs=163 +bigoakwoodstiars=164 +darkoakwoodstairs=164 +roofedoakwoodstairs=164 haybale=170 carpet=171 ironshovel=256 From d471ee8a9d93d1c793db316b00dcc8eddcdc2c2a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:38:57 +0200 Subject: [PATCH 226/751] 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 81492f70d1b1c11b7e9c73874cf497b786dff90d Mon Sep 17 00:00:00 2001 From: Masy98 Date: Thu, 21 Aug 2014 21:41:43 +0200 Subject: [PATCH 227/751] Changed new logs from wood to log! --- MCServer/items.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index 8f169157c..c4ee2c6e6 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -386,10 +386,10 @@ acacialeaves=161 bigoakleaves=161:1 darkoakleaves=161:1 roofedoakleaves=161:1 -acaciawood=162 -bigoakwood=162:1 -darkoakwood=162:1 -roofedoakwood=162:1 +acacialog=162 +bigoaklog=162:1 +darkoaklog=162:1 +roofedoaklog=162:1 acaciawoodstairs=163 bigoakwoodstiars=164 darkoakwoodstairs=164 From b4cc3a118b19f52b8a98b4322e10e1d6ffd75b71 Mon Sep 17 00:00:00 2001 From: Masy98 Date: Thu, 21 Aug 2014 21:50:32 +0200 Subject: [PATCH 228/751] Added missing recipes for stairs and slabs! --- MCServer/crafting.txt | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt index 60cda0673..c1a4b725e 100644 --- a/MCServer/crafting.txt +++ b/MCServer/crafting.txt @@ -44,6 +44,8 @@ ApplePlanks, 4 = AppleLog, * ConiferPlanks, 4 = ConiferLog, * BirchPlanks, 4 = BirchLog, * JunglePlanks, 4 = JungleLog, * +AcaciaPlanks, 4 = AcaciaLog, * +DarkOakPlanks, 4 = DarkOakLog, * Stick, 4 = Planks, 2:2, 2:3 Torch, 4 = Stick, 1:2 | Coal, 1:1 Workbench = Planks, 1:1, 1:2, 2:1, 2:2 @@ -74,11 +76,25 @@ PillarQuartzBlock = QuartzSlab, 1:1, 1:2 ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2 CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3 HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3 +SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2 +ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2 +BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2 +StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2 +BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2 +Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2 +SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2 +OrnamentSandstone = SandstoneSlab, 1:1, 1:2 +JackOLantern = Pumpkin, 1:1 | Torch, 1:2 # Slabs: StoneSlab, 6 = Stone, 1:1, 2:1, 3:1 SandstoneSlab, 6 = Sandstone, 1:1, 2:1, 3:1 -WoodSlab, 6 = Planks, 1:1, 2:1, 3:1 +OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1 +SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1 +BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1 +JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1 +AcacaciaWoodSlab,6 = AcaciaPlanks, 1:1, 2:1, 3:1 +DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1 CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1 BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1 StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1 @@ -86,9 +102,20 @@ 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 + # Stairs: -WoodStairs, 4 = Planks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 -WoodStairs, 4 = Planks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +WoodStairs, 4 = Planks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +WoodStairs, 4 = Planks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +SpruceWoodStairs, 4 = SprucePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +BirchWoodStairs, 4 = BirchPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +JungleWoodStairs, 4 = JunglePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +JungleWoodStairs, 4 = JunglePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +AcaciaWoodStairs, 4 = AcaciaPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +DarkOakWoodStairs, 4 = DarkOakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 cobblestoneStairs, 4 = Cobblestone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 @@ -101,15 +128,6 @@ quartzstairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 quartzstairs, 4 = QuartzBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 StoneBrickStairs, 4 = StoneBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 -SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2 -ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2 -BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2 -StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2 -BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2 -Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2 -SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2 -OrnamentSandstone = SandstoneSlab, 1:1, 1:2 -JackOLantern = Pumpkin, 1:1 | Torch, 1:2 # Other Carpet = Wool, 1:3, 2:3 From 81d238e0805eb8bd5ae3e844129bd11d62e1e8fd Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 21:53:25 +0200 Subject: [PATCH 229/751] 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 230/751] 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 940304bc64e6b64de7d9cd3f90362738c49df4ab Mon Sep 17 00:00:00 2001 From: Masy98 Date: Thu, 21 Aug 2014 22:08:34 +0200 Subject: [PATCH 231/751] Added missing recipes for stairs and slabs! --- MCServer/crafting.txt | 8 ++++---- MCServer/items.ini | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt index c1a4b725e..3cda9052b 100644 --- a/MCServer/crafting.txt +++ b/MCServer/crafting.txt @@ -89,12 +89,12 @@ JackOLantern = Pumpkin, 1:1 | Torch, 1:2 # Slabs: StoneSlab, 6 = Stone, 1:1, 2:1, 3:1 SandstoneSlab, 6 = Sandstone, 1:1, 2:1, 3:1 -OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1 SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1 BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1 JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1 -AcacaciaWoodSlab,6 = AcaciaPlanks, 1:1, 2:1, 3:1 +AcaciaWoodSlab, 6 = AcaciaPlanks, 1:1, 2:1, 3:1 DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1 +OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1 CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1 BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1 StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1 @@ -104,8 +104,6 @@ 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 -WoodStairs, 4 = Planks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 SpruceWoodStairs, 4 = SprucePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 @@ -116,6 +114,8 @@ AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 AcaciaWoodStairs, 4 = AcaciaPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 DarkOakWoodStairs, 4 = DarkOakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 +WoodStairs, 4 = OakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 +WoodStairs, 4 = OakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 cobblestoneStairs, 4 = Cobblestone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3 BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3 diff --git a/MCServer/items.ini b/MCServer/items.ini index c4ee2c6e6..9a61688ba 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -174,6 +174,7 @@ torch=50 fire=51 mobspawner=52 woodstairs=53 +oakwoodstairs=53 chest=54 redstonedust=55 redstonewire=55 From f71c76cf0559b5c5a932a8fd4a2c4038e24feb24 Mon Sep 17 00:00:00 2001 From: Masy98 Date: Thu, 21 Aug 2014 22:13:12 +0200 Subject: [PATCH 232/751] Fixed slab name --- MCServer/items.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index 9a61688ba..d3ae721f3 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -280,7 +280,7 @@ redstonelamp=123 redstonelampoff=123 redstonelampon=124 woodendoubleslab=125 -appledoublewood=125:0 +appledoublewoodslab=125:0 oakwooddoubleslab=125:0 coniferwooddoubleslab=125:1 pinewooddoubleslab=125:1 From 64fec204c4c5062461a7188b58026d062519b417 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 21 Aug 2014 22:39:53 +0200 Subject: [PATCH 233/751] 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 234/751] 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 235/751] 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 236/751] 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 237/751] 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 238/751] 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 7d771953c0e8275311ca13802e52ccf92a170644 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Fri, 22 Aug 2014 11:49:49 +0200 Subject: [PATCH 239/751] More Enchantments - Added Thorns and Respiration enchantments --- src/Blocks/BlockHandler.cpp | 1 - src/Entities/Entity.cpp | 135 ++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 0155aa97b..c8a57906f 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -433,7 +433,6 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac else { // TODO: Add a proper overridable function for this - // Pickups.Add(m_BlockType, 1, Meta); cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments; if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer()) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index a4c5c4b2a..760401cc2 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -357,8 +357,11 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case cMonster::mtSilverfish: { a_TDI.RawDamage += 2.5 * BaneOfArthropodsLevel; + // TODO: Add slowness effect + break; - } + }; + default: break; } } } @@ -390,8 +393,27 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) default: StartBurning(BurnTicks * 20); } } + } - + int ThornsLevel = 0; + cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; + for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) + { + cItem Item = ArmorItems[i]; + if (Item.m_Enchantments.GetLevel(cEnchantments::enchThorns) > ThornsLevel) ThornsLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchThorns); + } + + if (ThornsLevel > 0) + { + int Chance = ThornsLevel * 15; + + cFastRandom Random; + int RandomValue = Random.GenerateRandomInteger(0, 100); + + if (RandomValue <= Chance) + { + a_TDI.Attacker->TakeDamage(dtAttack, this, 0, Random.GenerateRandomInteger(1, 4), 0); + } } if (!Player->IsOnGround()) @@ -405,6 +427,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); } + if (IsPlayer()){ double TotalEPF = 0.0; double EPFProtection = 0.00; @@ -413,65 +436,39 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) double EPFProjectileProtection = 0.00; double EPFFeatherFalling = 0.00; - cEnchantments ChestplateEnchantments = GetEquippedChestplate().m_Enchantments; - cEnchantments LeggingsEnchantments = GetEquippedLeggings().m_Enchantments; - cEnchantments BootsEnchantments = GetEquippedBoots().m_Enchantments; - cEnchantments HelmetEnchantments = GetEquippedHelmet().m_Enchantments; - - if ((ChestplateEnchantments.GetLevel(cEnchantments::enchProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchProtection) > 0) - || (BootsEnchantments.GetLevel(cEnchantments::enchProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchProtection) > 0)) + cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; + for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) { - EPFProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; - EPFProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; - EPFProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; - EPFProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + cItem Item = ArmorItems[i]; + if (Item.m_Enchantments.GetLevel(cEnchantments::enchProtection) > 0) + { + EPFProtection += (6 + pow(Item.m_Enchantments.GetLevel(cEnchantments::enchProtection), 2)) * 0.75 / 3; + } + + if (Item.m_Enchantments.GetLevel(cEnchantments::enchFireProtection) > 0) + { + EPFFireProtection += (6 + pow(Item.m_Enchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; + } + + if (Item.m_Enchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) + { + EPFFeatherFalling += (6 + pow(Item.m_Enchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; + } + + if (Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) + { + EPFBlastProtection += (6 + pow(Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; + } + + if (Item.m_Enchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) + { + EPFProjectileProtection += (6 + pow(Item.m_Enchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; + } - TotalEPF += EPFProtection; } - if ((ChestplateEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) - || (BootsEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchFireProtection) > 0)) - { - EPFFireProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; - EPFFireProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; - EPFFireProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; - EPFFireProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchFireProtection), 2)) * 1.25 / 3; - - TotalEPF += EPFFireProtection; - } - - if ((ChestplateEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) - || (BootsEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchFeatherFalling) > 0)) - { - EPFFeatherFalling += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; - EPFFeatherFalling += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; - EPFFeatherFalling += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; - EPFFeatherFalling += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchFeatherFalling), 2)) * 2.5 / 3; - - TotalEPF += EPFFeatherFalling; - } - - if ((ChestplateEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) - || (BootsEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchBlastProtection) > 0)) - { - EPFBlastProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; - EPFBlastProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; - EPFBlastProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; - EPFBlastProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchBlastProtection), 2)) * 1.5 / 3; - - TotalEPF += EPFBlastProtection; - } - - if ((ChestplateEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) || (LeggingsEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) - || (BootsEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0) || (HelmetEnchantments.GetLevel(cEnchantments::enchProjectileProtection) > 0)) - { - EPFProjectileProtection += (6 + pow(ChestplateEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; - EPFProjectileProtection += (6 + pow(LeggingsEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; - EPFProjectileProtection += (6 + pow(BootsEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; - EPFProjectileProtection += (6 + pow(HelmetEnchantments.GetLevel(cEnchantments::enchProjectileProtection), 2)) * 1.5 / 3; - - TotalEPF += EPFProjectileProtection; - } + TotalEPF = EPFProtection + EPFFireProtection + EPFFeatherFalling + EPFBlastProtection + EPFProjectileProtection; + EPFProtection = EPFProtection / TotalEPF; EPFFireProtection = EPFFireProtection / TotalEPF; @@ -482,10 +479,9 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) if (TotalEPF > 25) TotalEPF = 25; cFastRandom Random; - float randomvalue; - randomvalue = Random.GenerateRandomInteger(50, 100) * 0.01; + float RandomValue = Random.GenerateRandomInteger(50, 100) * 0.01; - TotalEPF = ceil(TotalEPF * randomvalue); + TotalEPF = ceil(TotalEPF * RandomValue); if (TotalEPF > 20) TotalEPF = 20; @@ -507,9 +503,13 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) if (a_TDI.DamageType == dtProjectile) RemovedDamage += ceil(EPFBlastProtection * 0.04 * a_TDI.FinalDamage); + if (a_TDI.FinalDamage < RemovedDamage) RemovedDamage = 0; + a_TDI.FinalDamage -= RemovedDamage; } + + m_Health -= (short)a_TDI.FinalDamage; // TODO: Apply damage to armor @@ -533,7 +533,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) case 2: AdditionalSpeed.Set(8, 0.3, 8); break; default: break; } - SetSpeed(a_TDI.Knockback + AdditionalSpeed); + AddSpeed(a_TDI.Knockback + AdditionalSpeed); } m_World->BroadcastEntityStatus(*this, esGenericHurt); @@ -1435,6 +1435,8 @@ void cEntity::HandleAir(void) // See if the entity is /submerged/ water (block above is water) // Get the type of block the entity is standing in: + int RespirationLevel = GetEquippedHelmet().m_Enchantments.GetLevel(cEnchantments::enchRespiration); + if (IsSubmerged()) { if (!IsPlayer()) // Players control themselves @@ -1442,6 +1444,11 @@ void cEntity::HandleAir(void) SetSpeedY(1); // Float in the water } + if (RespirationLevel > 0) + { + ((cPawn *)this)->AddEntityEffect(cEntityEffect::effNightVision, 200, 5, 0); + } + if (m_AirLevel <= 0) { // Runs the air tick timer to check whether the player should be damaged @@ -1468,6 +1475,12 @@ void cEntity::HandleAir(void) // Set the air back to maximum m_AirLevel = MAX_AIR_LEVEL; m_AirTickTimer = DROWNING_TICKS; + + if (RespirationLevel > 0) + { + m_AirTickTimer = DROWNING_TICKS + (RespirationLevel * 15 * 20); + } + } } From 8fa4ac9ad957d951cf25c668ffbb4e5d2fafa7f7 Mon Sep 17 00:00:00 2001 From: Howaner Date: Fri, 22 Aug 2014 15:32:27 +0200 Subject: [PATCH 240/751] 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 241/751] 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 242/751] 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 243/751] 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 244/751] 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 245/751] 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 246/751] 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 247/751] 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 248/751] 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 249/751] 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 250/751] 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 251/751] 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 252/751] 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 253/751] 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 254/751] 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 255/751] 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 256/751] 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 257/751] 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 258/751] 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 259/751] 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 260/751] 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 261/751] 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 262/751] 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 263/751] 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 264/751] 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 265/751] 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 266/751] 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 267/751] 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 268/751] 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 269/751] 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 270/751] 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 0f1fd3312332da2a6104c9eb98625610a4a08eff Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 01:21:54 +0200 Subject: [PATCH 271/751] Enchanting table improvements. --- src/Item.cpp | 32 +++----- src/UI/SlotArea.cpp | 192 ++++++++++++++++++-------------------------- src/UI/SlotArea.h | 7 +- src/UI/Window.cpp | 33 ++++---- src/UI/Window.h | 3 - 5 files changed, 113 insertions(+), 154 deletions(-) diff --git a/src/Item.cpp b/src/Item.cpp index 2c5deaddf..a5117c271 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -190,31 +190,23 @@ void cItem::FromJson(const Json::Value & a_Value) -bool cItem::IsEnchantable(short item) +bool cItem::IsEnchantable(short a_ItemType) { - if ((item >= 256) && (item <= 259)) + if (ItemCategory::IsTool(a_ItemType) || ItemCategory::IsArmor(a_ItemType)) { return true; } - if ((item >= 267) && (item <= 279)) + + switch (a_ItemType) { - return true; - } - if ((item >= 283) && (item <= 286)) - { - return true; - } - if ((item >= 290) && (item <= 294)) - { - return true; - } - if ((item >= 298) && (item <= 317)) - { - return true; - } - if ((item == 346) || (item == 359) || (item == 261)) - { - return true; + case E_ITEM_BOOK: + case E_ITEM_BOW: + case E_ITEM_CARROT_ON_STICK: + case E_ITEM_FISHING_ROD: + case E_ITEM_SHEARS: + { + return true; + } } return false; diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 4199bbf56..74173d087 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -207,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ m_ParentWindow.DistributeStack(Slot, a_Player, this, true); if (Slot.IsEmpty()) { - // Empty the slot completely, the cilent doesn't like left-over ItemType with zero count + // Empty the slot completely, the client doesn't like left-over ItemType with zero count Slot.Empty(); } SetSlot(a_SlotNum, a_Player, Slot); @@ -1389,8 +1389,11 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) //////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnchanting: -cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) : - cSlotAreaTemporary(1, a_ParentWindow) +cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) : + cSlotAreaTemporary(1, a_ParentWindow), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) { a_ParentWindow.m_SlotArea = this; } @@ -1409,7 +1412,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); return; } - + switch (a_ClickAction) { case caShiftLeftClick: @@ -1420,7 +1423,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio } case caDblClick: { - DblClicked(a_Player, a_SlotNum); + // DblClicked(a_Player, a_SlotNum); return; } case caMiddleClick: @@ -1428,6 +1431,25 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio MiddleClicked(a_Player, a_SlotNum); return; } + case caDropKey: + case caCtrlDropKey: + { + DropClicked(a_Player, a_SlotNum, false); + return; + } + case caNumber1: + case caNumber2: + case caNumber3: + case caNumber4: + case caNumber5: + case caNumber6: + case caNumber7: + case caNumber8: + case caNumber9: + { + NumberClicked(a_Player, a_SlotNum, a_ClickAction); + return; + } default: { break; @@ -1443,107 +1465,38 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio bAsync = true; } cItem & DraggingItem = a_Player.GetDraggingItem(); - switch (a_ClickAction) + + if (DraggingItem.IsEmpty()) { - case caRightClick: + if (!Slot.IsEmpty()) { - // Right-clicked - if (DraggingItem.IsEmpty()) - { - DraggingItem = Slot.CopyOne(); - Slot.Empty(); - break; - } - - if (Slot.IsEmpty()) - { - Slot = DraggingItem.CopyOne(); - DraggingItem.m_ItemCount -= 1; - if (DraggingItem.m_ItemCount <= 0) - { - DraggingItem.Empty(); - } - } - else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1)) - { - // Swap contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - break; + DraggingItem = Slot; + Slot.Empty(); } - - case caLeftClick: + } + else if (Slot.IsEmpty()) + { + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + + if (DraggingItem.m_ItemCount <= 0) { - // Left-clicked - if (DraggingItem.IsEmpty()) - { - DraggingItem = Slot.CopyOne(); - Slot.Empty(); - break; - } - - if (DraggingItem.IsEqual(Slot)) - { - // Do nothing - break; - } - - if (!Slot.IsEmpty()) - { - if (DraggingItem.m_ItemCount == 1) - { - // Swap contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - } - else - { - Slot = DraggingItem.CopyOne(); - DraggingItem.m_ItemCount -= 1; - if (DraggingItem.m_ItemCount <= 0) - { - DraggingItem.Empty(); - } - } - break; + DraggingItem.Empty(); } - default: - { - LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); - m_ParentWindow.BroadcastWholeWindow(); - return; - } - } // switch (a_ClickAction - + } + else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot)) + { + // Switch contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + SetSlot(a_SlotNum, a_Player, Slot); if (bAsync) { m_ParentWindow.BroadcastWholeWindow(); } - UpdateResult(a_Player); -} - - - - - -void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum) -{ - cItem & Dragging = a_Player.GetDraggingItem(); - if ((!Dragging.IsEmpty()) || (a_SlotNum != 0)) - { - return; - } - - cItem Item = *GetSlot(0, a_Player); - if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false)) - { - m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true); - } } @@ -1567,7 +1520,15 @@ void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Playe { a_ItemStack.Empty(); } +} + + + + +void cSlotAreaEnchanting::OnPlayerAdded(cPlayer & a_Player) +{ + super::OnPlayerAdded(a_Player); UpdateResult(a_Player); } @@ -1587,29 +1548,33 @@ void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player) +void cSlotAreaEnchanting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) +{ + super::SetSlot(a_SlotNum, a_Player, a_Item); + UpdateResult(a_Player); +} + + + + + void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) { cItem Item = *GetSlot(0, a_Player); - if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty()) - { - m_ParentWindow.SetProperty(0, 0, a_Player); - m_ParentWindow.SetProperty(1, 0, a_Player); - m_ParentWindow.SetProperty(2, 0, a_Player); - } - else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK) + if (cItem::IsEnchantable(Item.m_ItemType) && Item.m_Enchantments.IsEmpty()) { int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15); cFastRandom Random; - int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); - int topSlot = std::max(base / 3, 1); - int middleSlot = (base * 2) / 3 + 1; - int bottomSlot = std::max(base, Bookshelves * 2); + int Base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); + int TopSlot = std::max(Base / 3, 1); + int MiddleSlot = (Base * 2) / 3 + 1; + int BottomSlot = std::max(Base, Bookshelves * 2); - m_ParentWindow.SetProperty(0, topSlot, a_Player); - m_ParentWindow.SetProperty(1, middleSlot, a_Player); - m_ParentWindow.SetProperty(2, bottomSlot, a_Player); + m_ParentWindow.SetProperty(0, TopSlot, a_Player); + m_ParentWindow.SetProperty(1, MiddleSlot, a_Player); + m_ParentWindow.SetProperty(2, BottomSlot, a_Player); } else { @@ -1625,12 +1590,9 @@ void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) { - int PosX, PosY, PosZ; - ((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); - int Bookshelves = 0; cBlockArea Area; - Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2); + Area.Read(a_World, m_BlockX - 2, m_BlockX + 2, m_BlockY, m_BlockY + 1, m_BlockZ - 2, m_BlockZ + 2); static const struct { @@ -1678,7 +1640,7 @@ int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) if ( (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place - ) + ) { Bookshelves++; } diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 9a96f2f3c..6bbc87b76 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -349,14 +349,15 @@ class cSlotAreaEnchanting : typedef cSlotAreaTemporary super; public: - cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow); + cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ); // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override; virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // cSlotAreaTemporary overrides: + virtual void OnPlayerAdded (cPlayer & a_Player) override; virtual void OnPlayerRemoved(cPlayer & a_Player) override; /* Get the count of bookshelves who stand in the near of the enchanting table */ @@ -365,6 +366,8 @@ public: protected: /** Handles a click in the item slot. */ void UpdateResult(cPlayer & a_Player); + + int m_BlockX, m_BlockY, m_BlockZ; }; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index 8f4913030..66900269f 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -881,7 +881,7 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : m_BlockY(a_BlockY), m_BlockZ(a_BlockZ) { - m_SlotAreas.push_back(new cSlotAreaEnchanting(*this)); + m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } @@ -892,8 +892,13 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : void cEnchantingWindow::SetProperty(int a_Property, int a_Value) { - m_PropertyValue[a_Property] = a_Value; + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + m_PropertyValue[a_Property] = a_Value; super::SetProperty(a_Property, a_Value); } @@ -903,8 +908,13 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value) void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) { - m_PropertyValue[a_Property] = a_Value; + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return; + } + m_PropertyValue[a_Property] = a_Value; super::SetProperty(a_Property, a_Value, a_Player); } @@ -914,6 +924,12 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Pla int cEnchantingWindow::GetPropertyValue(int a_Property) { + if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue))) + { + ASSERT(!"a_Property is invalid"); + return 0; + } + return m_PropertyValue[a_Property]; } @@ -921,17 +937,6 @@ int cEnchantingWindow::GetPropertyValue(int a_Property) -void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) -{ - a_PosX = m_BlockX; - a_PosY = m_BlockY; - a_PosZ = m_BlockZ; -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cChestWindow: diff --git a/src/UI/Window.h b/src/UI/Window.h index 9fb0e3b38..3d860407f 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -291,9 +291,6 @@ public: /** Return the Value of a Property */ int GetPropertyValue(int a_Property); - /** Get the Position from the Enchantment Table */ - void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); - cSlotArea * m_SlotArea; protected: From 3c1c073714e2b0542c9a79db962b6fc9e6ddd352 Mon Sep 17 00:00:00 2001 From: LO1ZB Date: Thu, 28 Aug 2014 11:36:35 +0200 Subject: [PATCH 272/751] remove y-coord from chunks --- src/Bindings/LuaChunkStay.cpp | 2 +- src/Chunk.cpp | 7 +- src/Chunk.h | 2 +- src/ChunkDef.h | 6 +- src/ChunkMap.cpp | 258 +++++++++++++++--------------- src/ChunkMap.h | 14 +- src/ChunkSender.cpp | 14 +- src/ChunkSender.h | 7 +- src/ChunkStay.cpp | 2 +- src/ClientHandle.cpp | 20 +-- src/ClientHandle.h | 2 +- src/Generating/ChunkGenerator.cpp | 14 +- src/Generating/ChunkGenerator.h | 4 +- src/World.cpp | 21 ++- src/World.h | 6 +- src/WorldStorage/WSSCompact.cpp | 6 +- src/WorldStorage/WorldStorage.cpp | 28 ++-- src/WorldStorage/WorldStorage.h | 12 +- 18 files changed, 208 insertions(+), 217 deletions(-) diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index 59b02d8f7..154bcb200 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -107,7 +107,7 @@ void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index) } } // for itr - m_Chunks[] - m_Chunks.push_back(cChunkCoords(ChunkX, ZERO_CHUNK_Y, ChunkZ)); + m_Chunks.push_back(cChunkCoords(ChunkX, ChunkZ)); } diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 116c0f3a0..5fd6cb352 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -65,7 +65,7 @@ sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_Bloc // cChunk: cChunk::cChunk( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World, cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, cAllocationPool & a_Pool @@ -77,7 +77,6 @@ cChunk::cChunk( m_HasLoadFailed(false), m_StayCount(0), m_PosX(a_ChunkX), - m_PosY(a_ChunkY), m_PosZ(a_ChunkZ), m_World(a_World), m_ChunkMap(a_ChunkMap), @@ -643,7 +642,7 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == NULL) { - Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Neighbor == NULL) { // TODO: What to do with this? @@ -2593,7 +2592,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; int ChunkX, ChunkZ; BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); - return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + return m_ChunkMap->GetChunkNoLoad(ChunkX, ChunkZ); } // Walk the neighbors: diff --git a/src/Chunk.h b/src/Chunk.h index 72a1f6c95..67b208fe5 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -67,7 +67,7 @@ class cChunk : { public: cChunk( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, // Chunk coords + int a_ChunkX, int a_ChunkZ, // Chunk coords cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool & a_Pool diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 51075ab4a..b7122efe2 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -19,7 +19,6 @@ /** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord. It will help us when the new chunk format comes out and we need to patch everything up for compatibility. */ -#define ZERO_CHUNK_Y 0 // Used to smoothly convert to new axis ordering. One will be removed when deemed stable. #define AXIS_ORDER_YZX 1 // Original (1.1-) @@ -377,14 +376,13 @@ class cChunkCoords { public: int m_ChunkX; - int m_ChunkY; int m_ChunkZ; - cChunkCoords(int a_ChunkX, int a_ChunkY, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ) {} + cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} bool operator == (const cChunkCoords & a_Other) const { - return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkY == a_Other.m_ChunkY) && (m_ChunkZ == a_Other.m_ChunkZ)); + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); } } ; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dd8be0631..e4ce6cbf5 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -143,7 +143,7 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk(int a_ChunkX, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) { // No need to lock m_CSLayers, since it's already locked by the operation that called us ASSERT(m_CSLayers.IsLockedByCurrentThread()); @@ -155,14 +155,14 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) return NULL; } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return NULL; } if (!(Chunk->IsValid())) { - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ, true); + m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ, true); } return Chunk; } @@ -171,7 +171,7 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkZ) { // No need to lock m_CSLayers, since it's already locked by the operation that called us cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); @@ -181,14 +181,14 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ) return NULL; } - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return NULL; } if (!(Chunk->IsValid())) { - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ, false); + m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ, false); } return Chunk; @@ -198,7 +198,7 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkZ) { // No need to lock m_CSLayers, since it's already locked by the operation that called us cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); @@ -208,7 +208,7 @@ cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ) return NULL; } - return Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + return Layer->GetChunk(a_ChunkX, a_ChunkZ); } @@ -222,7 +222,7 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -244,7 +244,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -265,7 +265,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -284,7 +284,7 @@ bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY // We already have m_CSLayers locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -303,7 +303,7 @@ bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLO // We already have m_CSLayers locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return false; @@ -336,7 +336,7 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -356,7 +356,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c x = a_BlockX; z = a_BlockZ; cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -375,7 +375,7 @@ void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -393,7 +393,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -408,7 +408,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, 0, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -424,7 +424,7 @@ void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -440,7 +440,7 @@ void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -456,7 +456,7 @@ void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHa void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -472,7 +472,7 @@ void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -488,7 +488,7 @@ void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotN void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -504,7 +504,7 @@ void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -520,7 +520,7 @@ void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandl void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -536,7 +536,7 @@ void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -552,7 +552,7 @@ void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, ch void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -568,7 +568,7 @@ void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -584,7 +584,7 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -600,7 +600,7 @@ void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -619,7 +619,7 @@ void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_ int ChunkX, ChunkZ; cChunkDef::BlockToChunk((int) a_SrcX, (int) a_SrcZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -636,7 +636,7 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -655,7 +655,7 @@ void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, do int ChunkX, ChunkZ; cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -674,7 +674,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -690,7 +690,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S void cChunkMap::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -708,7 +708,7 @@ void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, c cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -727,7 +727,7 @@ void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bl int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -745,7 +745,7 @@ void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClien cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -763,7 +763,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -778,7 +778,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return false; @@ -795,7 +795,7 @@ void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -824,7 +824,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M int MaxZ = std::min(a_MaxBlockZ, z * cChunkDef::Width + cChunkDef::Width - 1); for (int x = MinChunkX; x <= MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoGen(x, 0, z); + cChunkPtr Chunk = GetChunkNoGen(x, z); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -852,7 +852,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -867,7 +867,7 @@ void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -886,7 +886,7 @@ void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDi void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -901,7 +901,7 @@ void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -919,7 +919,7 @@ void cChunkMap::SetChunkData(cSetChunkData & a_SetChunkData) int ChunkZ = a_SetChunkData.GetChunkZ(); { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == NULL) { return; @@ -964,7 +964,7 @@ void cChunkMap::ChunkLighted( ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -980,7 +980,7 @@ void cChunkMap::ChunkLighted( bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -996,7 +996,7 @@ bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -1012,7 +1012,7 @@ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blo bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); return (Chunk != NULL) && Chunk->IsValid(); } @@ -1023,7 +1023,7 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); return (Chunk != NULL) && Chunk->HasAnyClients(); } @@ -1038,7 +1038,7 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if (Chunk == NULL) { return 0; @@ -1065,7 +1065,7 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -1088,7 +1088,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList) int ChunkX = a_BlockList.front().ChunkX; int ChunkZ = a_BlockList.front().ChunkZ; cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) @@ -1135,7 +1135,7 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) int BlockX = (int)(a_Player->GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway int BlockY = (int)(a_Player->GetPosY()); int BlockZ = (int)(a_Player->GetPosZ()); - int ChunkX, ChunkZ, ChunkY = ZERO_CHUNK_Y; + int ChunkX = 0, ChunkZ = 0; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); int OtherChunkX = ChunkX + ((BlockX > 8) ? 1 : -1); int OtherChunkZ = ChunkZ + ((BlockZ > 8) ? 1 : -1); @@ -1144,13 +1144,13 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) // The only time the chunks are not valid is when the player is downloading the initial world and they should not call this at that moment cCSLock Lock(m_CSLayers); - GetChunkNoLoad(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkZ)->CollectPickupsByPlayer(a_Player); // Check the neighboring chunks as well: - GetChunkNoLoad(OtherChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer (a_Player); - GetChunkNoLoad(OtherChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); - GetChunkNoLoad(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer (a_Player); - GetChunkNoLoad(ChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(OtherChunkX, ChunkZ)->CollectPickupsByPlayer (a_Player); + GetChunkNoLoad(OtherChunkX, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkZ)->CollectPickupsByPlayer (a_Player); + GetChunkNoLoad(ChunkX, OtherChunkZ)->CollectPickupsByPlayer(a_Player); } @@ -1177,7 +1177,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); @@ -1206,7 +1206,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); @@ -1224,7 +1224,7 @@ NIBBLETYPE cChunkMap::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetSkyLight(a_BlockX, a_BlockY, a_BlockZ); @@ -1242,7 +1242,7 @@ NIBBLETYPE cChunkMap::GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_Block cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBlockLight(a_BlockX, a_BlockY, a_BlockZ); @@ -1261,7 +1261,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP // a_BlockXYZ now contains relative coords! cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); @@ -1284,7 +1284,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); @@ -1303,7 +1303,7 @@ void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYP cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->QueueSetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType); @@ -1320,7 +1320,7 @@ bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->GetBlockTypeMeta(X, Y, Z, a_BlockType, a_BlockMeta); @@ -1339,7 +1339,7 @@ bool cChunkMap::GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->GetBlockInfo(X, Y, Z, a_BlockType, a_Meta, a_SkyLight, a_BlockLight); @@ -1357,7 +1357,7 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt cCSLock Lock(m_CSLayers); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -1378,7 +1378,7 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) cCSLock Lock(m_CSLayers); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { continue; @@ -1413,7 +1413,7 @@ EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { return Chunk->GetBiomeAt(X, Z); @@ -1434,7 +1434,7 @@ bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetBiomeAt(X, Z, a_Biome); @@ -1467,7 +1467,7 @@ bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMC { int MinRelZ = (z == MinChunkZ) ? MinZ : 0; int MaxRelZ = (z == MaxChunkZ) ? MaxZ : cChunkDef::Width - 1; - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetAreaBiome(MinRelX, MaxRelX, MinRelZ, MaxRelZ, a_Biome); @@ -1491,7 +1491,7 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) cCSLock Lock(m_CSLayers); for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ); + cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { if (!a_ContinueOnFailure) @@ -1519,7 +1519,7 @@ bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z) { cCSLock Lock(m_CSLayers); - cChunkPtr DestChunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr DestChunk = GetChunk( ChunkX, ChunkZ); if ((DestChunk == NULL) || !DestChunk->IsValid()) { return false; @@ -1542,7 +1542,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) cChunkDef::AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != NULL) && (Chunk->IsValid())) { Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle()); @@ -1556,12 +1556,12 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, ZERO_CHUNK_Y, a_ChunkZ1); + cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkZ1); if (Chunk1 == NULL) { return; } - cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, ZERO_CHUNK_Y, a_ChunkZ2); + cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, a_ChunkZ2); if (Chunk2 == NULL) { return; @@ -1623,7 +1623,7 @@ void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClien bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return false; @@ -1638,7 +1638,7 @@ bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Cli void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -1667,7 +1667,7 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) void cChunkMap::AddEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( (Chunk == NULL) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) @@ -1688,7 +1688,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity) void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if ( (Chunk == NULL) || // Chunk not present at all (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) @@ -1729,7 +1729,7 @@ bool cChunkMap::HasEntity(int a_UniqueID) void cChunkMap::RemoveEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) if (Chunk == NULL) @@ -1763,7 +1763,7 @@ bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback) bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2011,7 +2011,7 @@ bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2026,7 +2026,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2041,7 +2041,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2056,7 +2056,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2071,7 +2071,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2086,7 +2086,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2104,7 +2104,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2122,7 +2122,7 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeacon int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2140,7 +2140,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2158,7 +2158,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2176,7 +2176,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2194,7 +2194,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2212,7 +2212,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2229,7 +2229,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2246,7 +2246,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2264,7 +2264,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2282,7 +2282,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2300,7 +2300,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2312,10 +2312,10 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & -void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + GetChunk(a_ChunkX, a_ChunkZ); } @@ -2323,11 +2323,11 @@ void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) /// Loads the chunk synchronously, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) -bool cChunkMap::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cChunkMap::LoadChunk(int a_ChunkX, int a_ChunkZ) { { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { // Internal error @@ -2344,7 +2344,7 @@ bool cChunkMap::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) return false; } } - return m_World->GetStorage().LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + return m_World->GetStorage().LoadChunk(a_ChunkX, a_ChunkZ); } @@ -2356,7 +2356,7 @@ void cChunkMap::LoadChunks(const cChunkCoordsList & a_Chunks) { for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr) { - LoadChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + LoadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - a_Chunks[] } @@ -2364,10 +2364,10 @@ void cChunkMap::LoadChunks(const cChunkCoordsList & a_Chunks) -void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { return; @@ -2384,7 +2384,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -2399,7 +2399,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { // Not present @@ -2415,7 +2415,7 @@ void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) bool cChunkMap::IsChunkLighted(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == NULL) { // Not present @@ -2436,7 +2436,7 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh { for (int x = a_MinChunkX; x <= a_MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { // Not present / not valid @@ -2478,7 +2478,7 @@ bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBl { for (int x = MinChunkX; x <= MaxChunkX; x++) { - cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z); + cChunkPtr Chunk = GetChunkNoLoad(x, z); if ((Chunk == NULL) || (!Chunk->IsValid())) { // Not present / not valid @@ -2519,7 +2519,7 @@ void cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand); @@ -2536,7 +2536,7 @@ void cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Nu cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); @@ -2553,7 +2553,7 @@ void cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBl cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow); @@ -2570,7 +2570,7 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->SetNextBlockTick(a_BlockX, a_BlockY, a_BlockZ); @@ -2625,7 +2625,7 @@ void cChunkMap::TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -2694,7 +2694,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) // a_BlockXYZ now contains relative coords! cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != NULL) { Chunk->QueueTickBlock(a_BlockX, a_BlockY, a_BlockZ); @@ -2708,7 +2708,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk != NULL) { Chunk->SetAlwaysTicked(a_AlwaysTicked); @@ -2753,7 +2753,7 @@ cChunkMap::cChunkLayer::~cChunkLayer() -cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ) +cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ) { // Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check @@ -2773,7 +2773,7 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ - 1); cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ + 1); - m_Chunks[Index] = new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); + m_Chunks[Index] = new cChunk(a_ChunkX, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); } return m_Chunks[Index]; } @@ -2973,7 +2973,7 @@ void cChunkMap::cChunkLayer::Save(void) { if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) { - World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosY(), m_Chunks[i]->GetPosZ()); + World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()); } } // for i - m_Chunks[] } @@ -3046,7 +3046,7 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) const cChunkCoordsVector & WantedChunks = a_ChunkStay.GetChunks(); for (cChunkCoordsVector::const_iterator itr = WantedChunks.begin(); itr != WantedChunks.end(); ++itr) { - cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); if (Chunk == NULL) { continue; @@ -3095,7 +3095,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) const cChunkCoordsVector & Chunks = a_ChunkStay.GetChunks(); for (cChunkCoordsVector::const_iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr) { - cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkZ); if (Chunk == NULL) { continue; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 1e9a0f982..6a379e51d 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -270,16 +270,16 @@ public: bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible /** Touches the chunk, causing it to be loaded or generated */ - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void TouchChunk(int a_ChunkX, int a_ChunkZ); /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool LoadChunk(int a_ChunkX, int a_ChunkZ); /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ void LoadChunks(const cChunkCoordsList & a_Chunks); /** Marks the chunk as failed-to-load */ - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); /** Sets the sign text. Returns true if sign text changed. */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); @@ -363,7 +363,7 @@ private: ~cChunkLayer(); /** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */ - cChunkPtr GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ); + cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ); /** Returns the specified chunk, or NULL if not created yet */ cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); @@ -456,9 +456,9 @@ private: std::auto_ptr > m_Pool; - cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid - cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate - cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate + cChunkPtr GetChunk (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid + cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate + cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); // Doesn't load, doesn't generate /** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp index ebcf0e272..95c4d03d2 100644 --- a/src/ChunkSender.cpp +++ b/src/ChunkSender.cpp @@ -81,7 +81,7 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ) // This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check { cCSLock Lock(m_CS); - m_ChunksReady.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } m_evtQueue.Set(); } @@ -95,12 +95,12 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * ASSERT(a_Client != NULL); { cCSLock Lock(m_CS); - if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)) != m_SendChunks.end()) + if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, a_ChunkZ, a_Client)) != m_SendChunks.end()) { // Already queued, bail out return; } - m_SendChunks.push_back(sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)); + m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkZ, a_Client)); } m_evtQueue.Set(); } @@ -160,7 +160,7 @@ void cChunkSender::Execute(void) m_ChunksReady.pop_front(); Lock.Unlock(); - SendChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, NULL); + SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, NULL); } else { @@ -169,7 +169,7 @@ void cChunkSender::Execute(void) m_SendChunks.pop_front(); Lock.Unlock(); - SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client); + SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client); } Lock.Lock(); int RemoveCount = m_RemoveCount; @@ -186,14 +186,14 @@ void cChunkSender::Execute(void) -void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { ASSERT(m_World != NULL); // Ask the client if it still wants the chunk: if (a_Client != NULL) { - if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ)) { return; } diff --git a/src/ChunkSender.h b/src/ChunkSender.h index 624a3a0bd..a0e9087a9 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -95,13 +95,11 @@ protected: struct sSendChunk { int m_ChunkX; - int m_ChunkY; int m_ChunkZ; cClientHandle * m_Client; - sSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) : + sSendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) : m_ChunkX(a_ChunkX), - m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Client(a_Client) { @@ -111,7 +109,6 @@ protected: { return ( (a_Other.m_ChunkX == m_ChunkX) && - (a_Other.m_ChunkY == m_ChunkY) && (a_Other.m_ChunkZ == m_ChunkZ) && (a_Other.m_Client == m_Client) ); @@ -162,7 +159,7 @@ protected: virtual void BlockEntity (cBlockEntity * a_Entity) override; /// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL - void SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); } ; diff --git a/src/ChunkStay.cpp b/src/ChunkStay.cpp index b5002a63d..38aa89a37 100644 --- a/src/ChunkStay.cpp +++ b/src/ChunkStay.cpp @@ -51,7 +51,7 @@ void cChunkStay::Add(int a_ChunkX, int a_ChunkZ) return; } } // for itr - Chunks[] - m_Chunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_Chunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8aa883144..18c1a32ef 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -472,13 +472,13 @@ void cClientHandle::StreamChunks(void) // For each distance touch chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - World->TouchChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); - World->TouchChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); + World->TouchChunk(ChunkPosX + d, ChunkPosZ + i); + World->TouchChunk(ChunkPosX - d, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); - World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); + World->TouchChunk(ChunkPosX + i, ChunkPosZ + d); + World->TouchChunk(ChunkPosX + i, ChunkPosZ - d); } // for i } // for d } @@ -501,8 +501,8 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) { { cCSLock Lock(m_CSChunkLists); - m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } World->SendChunkTo(a_ChunkX, a_ChunkZ, this); } @@ -2733,7 +2733,7 @@ bool cClientHandle::HasPluginChannel(const AString & a_PluginChannel) -bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkZ) { if (m_State >= csDestroying) { @@ -2741,7 +2741,7 @@ bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) } cCSLock Lock(m_CSChunkLists); - return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)) != m_ChunksToSend.end()); + return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) != m_ChunksToSend.end()); } @@ -2757,9 +2757,9 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ) LOGD("Adding chunk [%d, %d] to wanted chunks for client %p", a_ChunkX, a_ChunkZ, this); cCSLock Lock(m_CSChunkLists); - if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)) == m_ChunksToSend.end()) + if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) == m_ChunksToSend.end()) { - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 7ae70a07f..e98d7be99 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -209,7 +209,7 @@ public: // tolua_end /** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */ - bool WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool WantsSendChunk(int a_ChunkX, int a_ChunkZ); /** Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) */ void AddWantedChunk(int a_ChunkX, int a_ChunkZ); diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index a1188f984..4d0cf3192 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -99,7 +99,7 @@ void cChunkGenerator::Stop(void) -void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ) { { cCSLock Lock(m_CS); @@ -107,7 +107,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk // Check if it is already in the queue: for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { - if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ)) + if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) { // Already in the queue, bail out return; @@ -119,7 +119,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk { LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size()); } - m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ)); } m_Event.Set(); @@ -246,7 +246,7 @@ void cChunkGenerator::Execute(void) } // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) + if (m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request @@ -259,8 +259,8 @@ void cChunkGenerator::Execute(void) continue; } - LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGD("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); + DoGenerate(coords.m_ChunkX, coords.m_ChunkZ); NumChunksGenerated++; } // while (!bStop) @@ -269,7 +269,7 @@ void cChunkGenerator::Execute(void) -void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ) { ASSERT(m_PluginInterface != NULL); ASSERT(m_ChunkSink != NULL); diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h index 88d71f3f9..17ca8adce 100644 --- a/src/Generating/ChunkGenerator.h +++ b/src/Generating/ChunkGenerator.h @@ -116,7 +116,7 @@ public: void Stop(void); /// Queues the chunk for generation; removes duplicate requests - void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ); /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap); @@ -154,7 +154,7 @@ private: // cIsThread override: virtual void Execute(void) override; - void DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void DoGenerate(int a_ChunkX, int a_ChunkZ); }; diff --git a/src/World.cpp b/src/World.cpp index 69d1217f1..eba3a8357 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -442,7 +442,7 @@ void cWorld::InitializeSpawn(void) { for (int z = 0; z < ViewDist; z++) { - m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader + m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader } } @@ -2421,7 +2421,7 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) // Save the chunk right after generating, so that we don't have to generate it again on next run if (a_SetChunkData.ShouldMarkDirty()) { - m_Storage.QueueSaveChunk(ChunkX, 0, ChunkZ); + m_Storage.QueueSaveChunk(ChunkX, ChunkZ); } } @@ -2766,18 +2766,18 @@ void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client) -void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ); } -bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkZ) { - return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkZ); } @@ -2793,9 +2793,9 @@ void cWorld::LoadChunks(const cChunkCoordsList & a_Chunks) -void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkZ); } @@ -2900,8 +2900,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) { m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ); - // Trick: use Y=1 to force the chunk generation even though the chunk data is already present - m_Generator.QueueGenerateChunk(a_ChunkX, 1, a_ChunkZ); + m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ); } @@ -2910,7 +2909,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) { - m_Generator.QueueGenerateChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ); } diff --git a/src/World.h b/src/World.h index 578c9682b..50b157312 100644 --- a/src/World.h +++ b/src/World.h @@ -351,16 +351,16 @@ public: void RemoveClientFromChunkSender(cClientHandle * a_Client); /** Touches the chunk, causing it to be loaded or generated */ - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void TouchChunk(int a_ChunkX, int a_ChunkZ); /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool LoadChunk(int a_ChunkX, int a_ChunkZ); /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ void LoadChunks(const cChunkCoordsList & a_Chunks); /** Marks the chunk as failed-to-load: */ - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ); /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index 58f9e3cab..6760186b2 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -980,7 +980,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer)) { // Chunk not valid - LOG("cWSSCompact: Trying to save chunk [%d, %d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOG("cWSSCompact: Trying to save chunk [%d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -999,7 +999,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { - LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -1010,7 +1010,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld sChunkHeader * Header = new sChunkHeader; if (Header == NULL) { - LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); + LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } Header->m_CompressedSize = (int)CompressedData.size(); diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 707e8f929..c4df8c379 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -141,9 +141,9 @@ size_t cWorldStorage::GetSaveQueueLength(void) -void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) +void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ, bool a_Generate) { - m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); + m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkZ, a_Generate)); m_Event.Set(); } @@ -151,9 +151,9 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, boo -void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ) { - m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkZ)); m_Event.Set(); } @@ -161,9 +161,9 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ) { - m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, true)); + m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkZ, true)); } @@ -242,19 +242,19 @@ void cWorldStorage::Execute(void) bool cWorldStorage::LoadOneChunk(void) { - sChunkLoad ToLoad(0, 0, 0, false); + sChunkLoad ToLoad(0, 0, false); bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad); - if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ)) + if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ)) { if (ToLoad.m_Generate) { // The chunk couldn't be loaded, generate it: - m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); + m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ); } else { // TODO: Notify the world that the load has failed: - // m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ); + // m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkZ); } } return ShouldLoad; @@ -266,7 +266,7 @@ bool cWorldStorage::LoadOneChunk(void) bool cWorldStorage::SaveOneChunk(void) { - cChunkCoords ToSave(0, 0, 0); + cChunkCoords ToSave(0, 0); bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave); if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ)) { @@ -283,7 +283,7 @@ bool cWorldStorage::SaveOneChunk(void) -bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkZ) { if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) { @@ -291,7 +291,7 @@ bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) return true; } - cChunkCoords Coords(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkCoords Coords(a_ChunkX, a_ChunkZ); // First try the schema that is used for saving if (m_SaveSchema->LoadChunk(Coords)) @@ -309,7 +309,7 @@ bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) } // Notify the chunk owner that the chunk failed to load (sets cChunk::m_HasLoadFailed to true): - m_World->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ); + m_World->ChunkLoadFailed(a_ChunkX, a_ChunkZ); return false; } diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index dd07ecb64..5f89ead53 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -64,13 +64,13 @@ public: cWorldStorage(void); ~cWorldStorage(); - void QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true - void QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void QueueLoadChunk(int a_ChunkX, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true + void QueueSaveChunk(int a_ChunkX, int a_ChunkZ); /// Loads the chunk specified; returns true on success, false on failure - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool LoadChunk(int a_ChunkX, int a_ChunkZ); - void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void UnqueueLoad(int a_ChunkX, int a_ChunkZ); void UnqueueSave(const cChunkCoords & a_Chunk); bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args @@ -87,17 +87,15 @@ protected: struct sChunkLoad { int m_ChunkX; - int m_ChunkY; int m_ChunkZ; bool m_Generate; // If true, the chunk will be generated if it cannot be loaded - sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} + sChunkLoad(int a_ChunkX, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {} bool operator ==(const sChunkLoad other) const { return ( (this->m_ChunkX == other.m_ChunkX) && - (this->m_ChunkY == other.m_ChunkY) && (this->m_ChunkZ == other.m_ChunkZ) ); } From 6c3b80f04c7c2cca26efb57cc9827a7a1d20fcda Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 14:58:03 +0200 Subject: [PATCH 273/751] Fixed crashes and use std::swap. --- src/ClientHandle.cpp | 22 +++++++++++++++++++--- src/ClientHandle.h | 2 +- src/Item.cpp | 36 ++++++++++++++++++++---------------- src/UI/SlotArea.cpp | 9 +++------ 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8aa883144..1dd8ff31c 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2857,11 +2857,27 @@ void cClientHandle::SocketClosed(void) -void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment) +void cClientHandle::HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment) { - cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow(); + if (a_Enchantment > 2) + { + LOGWARNING("%s attempt to crash the server with invalid enchanting selection!", GetUsername().c_str()); + Kick("Invalid enchanting!"); + return; + } + + if ( + (m_Player->GetWindow() == NULL) || + (m_Player->GetWindow()->GetWindowID() != a_WindowID) || + (m_Player->GetWindow()->GetWindowType() != cWindow::wtEnchantment) + ) + { + return; + } + + cEnchantingWindow * Window = (cEnchantingWindow*) m_Player->GetWindow(); cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player); - int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment); + int BaseEnchantmentLevel = Window->GetPropertyValue(a_Enchantment); if (Item.EnchantByXPLevels(BaseEnchantmentLevel)) { diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 7ae70a07f..24031119d 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -269,7 +269,7 @@ public: void RemoveFromWorld(void); /** Called when the player will enchant a Item */ - void HandleEnchantItem(Byte & WindowID, Byte & Enchantment); + void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment); private: diff --git a/src/Item.cpp b/src/Item.cpp index a5117c271..4d29318e6 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -291,73 +291,77 @@ int cItem::GetEnchantability() bool cItem::EnchantByXPLevels(int a_NumXPLevels) { - if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK)) + if (!cItem::IsEnchantable(m_ItemType)) { return false; } int Enchantability = GetEnchantability(); + if (Enchantability == 0) + { + return false; + } cFastRandom Random; int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1; float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F; int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F); - cWeightedEnchantments enchantments; - cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel); + cWeightedEnchantments Enchantments; + cEnchantments::AddItemEnchantmentWeights(Enchantments, m_ItemType, FinalEnchantmentLevel); if (m_ItemType == E_ITEM_BOOK) { m_ItemType = E_ITEM_ENCHANTED_BOOK; } - cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment1.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment1); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment1); float NewEnchantmentLevel = (float)a_NumXPLevels; // Next Enchantment (Second) NewEnchantmentLevel = NewEnchantmentLevel / 2; float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance)) { return true; } - cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment2.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment2); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment2); // Next Enchantment (Third) NewEnchantmentLevel = NewEnchantmentLevel / 2; float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance)) { return true; } - cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment3.ToString()); - cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3); + cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment3); // Checking for conflicting enchantments - cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3); + cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment3); // Next Enchantment (Fourth) NewEnchantmentLevel = NewEnchantmentLevel / 2; float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; - if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance)) + if (Enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance)) { return true; } - cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments); m_Enchantments.AddFromString(Enchantment4.ToString()); return true; diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 74173d087..88af257a0 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -1423,7 +1423,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio } case caDblClick: { - // DblClicked(a_Player, a_SlotNum); + DblClicked(a_Player, a_SlotNum); return; } case caMiddleClick: @@ -1470,8 +1470,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio { if (!Slot.IsEmpty()) { - DraggingItem = Slot; - Slot.Empty(); + std::swap(DraggingItem, Slot); } } else if (Slot.IsEmpty()) @@ -1487,9 +1486,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot)) { // Switch contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; + std::swap(DraggingItem, Slot); } SetSlot(a_SlotNum, a_Player, Slot); From f1470fcf9f1dc907241a645614cdcd5547dc1dbd Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 15:21:38 +0200 Subject: [PATCH 274/751] Fixed bad values in the IsEnchantable() method. --- src/Item.cpp | 20 ++++++++++++++++---- src/Item.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Item.cpp b/src/Item.cpp index 4d29318e6..ebdf99ca5 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -190,9 +190,16 @@ void cItem::FromJson(const Json::Value & a_Value) -bool cItem::IsEnchantable(short a_ItemType) +bool cItem::IsEnchantable(short a_ItemType, bool a_WithBook) { - if (ItemCategory::IsTool(a_ItemType) || ItemCategory::IsArmor(a_ItemType)) + if ( + ItemCategory::IsAxe(a_ItemType) || + ItemCategory::IsSword(a_ItemType) || + ItemCategory::IsShovel(a_ItemType) || + ItemCategory::IsPickaxe(a_ItemType) || + (a_WithBook && ItemCategory::IsHoe(a_ItemType)) || + ItemCategory::IsArmor(a_ItemType) + ) { return true; } @@ -201,12 +208,17 @@ bool cItem::IsEnchantable(short a_ItemType) { case E_ITEM_BOOK: case E_ITEM_BOW: - case E_ITEM_CARROT_ON_STICK: case E_ITEM_FISHING_ROD: - case E_ITEM_SHEARS: { return true; } + + case E_ITEM_CARROT_ON_STICK: + case E_ITEM_SHEARS: + case E_ITEM_FLINT_AND_STEEL: + { + return a_WithBook; + } } return false; diff --git a/src/Item.h b/src/Item.h index d8b9e78a0..61011d861 100644 --- a/src/Item.h +++ b/src/Item.h @@ -184,7 +184,7 @@ public: void FromJson(const Json::Value & a_Value); /** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */ - static bool IsEnchantable(short a_ItemType); // tolua_export + static bool IsEnchantable(short a_ItemType, bool a_WithBook = false); // tolua_export /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */ int GetEnchantability(); // tolua_export From c0c4ac5236779af648fd64d32eb7075553e4a88a Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 15:21:50 +0200 Subject: [PATCH 275/751] Added comments. --- src/UI/SlotArea.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 88af257a0..b4facb2d3 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -1468,6 +1468,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio if (DraggingItem.IsEmpty()) { + // DraggingItem is empty -> Switch draggingitem and slot if (!Slot.IsEmpty()) { std::swap(DraggingItem, Slot); @@ -1475,6 +1476,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio } else if (Slot.IsEmpty()) { + // DraggingItem isn't empty and slot is empty -> Set one dragging item in the slot Slot = DraggingItem.CopyOne(); DraggingItem.m_ItemCount -= 1; @@ -1485,7 +1487,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio } else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot)) { - // Switch contents + // DraggingItem and slot aren't empty -> Switch items std::swap(DraggingItem, Slot); } From 49ac6fadfc441e1de1a0127ff45996ac3abae150 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 28 Aug 2014 16:44:36 +0300 Subject: [PATCH 276/751] 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 277/751] 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 278/751] 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 279/751] 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 280/751] 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 4ff34b9f10368587b7d7ade58977fb8ec7692d73 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 18:18:21 +0200 Subject: [PATCH 281/751] APIDump: Added missing cItem things. --- MCServer/Plugins/APIDump/APIDesc.lua | 11 ++++++++--- src/Item.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 3e1a6e3bb..d75911666 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1188,7 +1188,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins, constructor = { { Params = "", Return = "cItem", Notes = "Creates a new empty cItem object" }, - { Params = "ItemType, Count, Damage, EnchantmentString", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default) and enchantments (non-enchanted by default)" }, + { Params = "ItemType, Count, Damage, EnchantmentString, CustomName, Lore", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default), enchantments (non-enchanted by default), CustomName (empty by default) and Lore (string, empty by default)" }, { Params = "cItem", Return = "cItem", Notes = "Creates an exact copy of the cItem object in the parameter" }, } , AddCount = { Params = "AmountToAdd", Return = "cItem", Notes = "Adds the specified amount to the item count. Returns self (useful for chaining)." }, @@ -1207,6 +1207,9 @@ These ItemGrids are available in the API and can be manipulated by the plugins, IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." }, IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." }, IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." }, + GetEnchantability = { Params = "", Return = "number", Notes = "Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0" }, + EnchantByXPLevels = { Params = "NumXPLevels", Return = "bool", Notes = "Enchants the item using the specified number of XP levels. Returns true if item enchanted, false if not." }, + IsEnchantable = { Params = "ItemType, WithBook", Return = "bool", Notes = "(STATIC) Returns true if the specified item type is enchantable." }, }, Variables = { @@ -1214,8 +1217,10 @@ These ItemGrids are available in the API and can be manipulated by the plugins, m_ItemCount = { Type = "number", Notes = "Number of items in this stack" }, m_ItemDamage = { Type = "number", Notes = "The damage of the item. Zero means no damage. Maximum damage can be queried with GetMaxDamage()" }, m_ItemType = { Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants" }, - m_CustomName = { Type = "string", Notes = "The custom name for an item." }, - m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." }, + m_CustomName = { Type = "string", Notes = "The custom name for an item." }, + m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." }, + m_RepairCost = { Type = "number", Notes = "The repair cost of the item. The anvil need this value" }, + m_Enchantments = { Type = "{{cEnchantments|cEnchantments}}}", Notes = "The enchantments of the item." }, }, AdditionalInfo = { diff --git a/src/Item.h b/src/Item.h index 61011d861..316928b9e 100644 --- a/src/Item.h +++ b/src/Item.h @@ -183,7 +183,7 @@ public: /** Loads the item data from JSON representation */ void FromJson(const Json::Value & a_Value); - /** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */ + /** Returns true if the specified item type is enchantable. */ static bool IsEnchantable(short a_ItemType, bool a_WithBook = false); // tolua_export /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */ From eaf33e22cf65178d94aafab3df5d8a9f67581529 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 18:57:56 +0200 Subject: [PATCH 282/751] 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 283/751] 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 240ec9b4bdd70f29aea3340f8f684818022122fd Mon Sep 17 00:00:00 2001 From: Hownaer Date: Thu, 28 Aug 2014 23:02:20 +0200 Subject: [PATCH 284/751] Added speed entity effect. --- src/ClientHandle.cpp | 2 +- src/Entities/EntityEffect.cpp | 41 +++++++++++++++++++++++++++++++++++ src/Entities/EntityEffect.h | 4 ++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f9c6a664c..5ad9dc644 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1063,7 +1063,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc (m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_FIRE) ) { - // Players can't destroy blocks with a Sword in the hand. + // Players can't destroy blocks with a sword in the hand. return; } diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index 3e28392f4..58b76b21b 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -232,6 +232,47 @@ void cEntityEffect::OnTick(cPawn & a_Target) +//////////////////////////////////////////////////////////////////////////////// +// cEntityEffectSpeed: + +void cEntityEffectSpeed::OnActivate(cPawn & a_Target) +{ + // TODO: Add SetMormalMaxSpeed to cMonster + + if (!a_Target.IsPlayer()) + { + return; + } + cPlayer * Player = (cPlayer*) &a_Target; + + Player->SetNormalMaxSpeed(1.0 + 0.2 * m_Intensity); + Player->SetSprintingMaxSpeed(1.3 + 0.26 * m_Intensity); + Player->SetFlyingMaxSpeed(1.0 + 0.2 * m_Intensity); +} + + + + + +void cEntityEffectSpeed::OnDeactivate(cPawn & a_Target) +{ + // TODO: Add SetMormalMaxSpeed to cMonster + + if (!a_Target.IsPlayer()) + { + return; + } + cPlayer * Player = (cPlayer*) &a_Target; + + Player->SetNormalMaxSpeed(1.0); + Player->SetSprintingMaxSpeed(1.3); + Player->SetFlyingMaxSpeed(1.0); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cEntityEffectInstantHealth: diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h index 47c298f57..e123a7f77 100644 --- a/src/Entities/EntityEffect.h +++ b/src/Entities/EntityEffect.h @@ -137,6 +137,10 @@ public: super(a_Duration, a_Intensity, a_DistanceModifier) { } + + virtual void OnActivate(cPawn & a_Target) override; + + virtual void OnDeactivate(cPawn & a_Target) override; }; From c4d7f7996b0dcd784f5e1ccc8553b062c3ac96b6 Mon Sep 17 00:00:00 2001 From: Hownaer Date: Fri, 29 Aug 2014 00:42:33 +0200 Subject: [PATCH 285/751] 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 286/751] 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 287/751] 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 288/751] 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 fca5a01145f78a4ae517da6c19ee61ab54574e82 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:41:50 +0100 Subject: [PATCH 289/751] Improved command block security --- src/BlockEntities/CommandBlockEntity.cpp | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 45f8a3e4d..fe2f5e60a 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -13,6 +13,7 @@ #include "../Root.h" #include "../Server.h" // ExecuteConsoleCommand() #include "../Chunk.h" +#include "../ChatColor.h" @@ -206,15 +207,27 @@ void cCommandBlockEntity::Execute() virtual void Out(const AString & a_Text) { // Overwrite field - m_CmdBlock->SetLastOutput(a_Text); + m_CmdBlock->SetLastOutput(cClientHandle::FormatChatPrefix(m_CmdBlock->GetWorld()->ShouldUseChatPrefixes(), "SUCCESS", cChatColor::Green, cChatColor::White) + a_Text); } } CmdBlockOutCb(this); - LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); - - cServer * Server = cRoot::Get()->GetServer(); - - Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + if ( // Administrator commands are not executable by command blocks + (m_Command != "stop") && + (m_Command != "restart") && + (m_Command != "kick") && + (m_Command != "ban") && + (m_Command != "ipban") + ) + { + cServer * Server = cRoot::Get()->GetServer(); + LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); + Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + } + else + { + SetLastOutput(cClientHandle::FormatChatPrefix(GetWorld()->ShouldUseChatPrefixes(), "FAILURE", cChatColor::Rose, cChatColor::White) + "Adminstration commands can not be executed"); + LOGD("cCommandBlockEntity: Prevented execution of administration command %s", m_Command.c_str()); + } // TODO 2014-01-18 xdot: Update the signal strength. m_Result = 0; From 114b14faad854661040a3a65c027d6b3fa818f56 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:44:01 +0100 Subject: [PATCH 290/751] Removed unused code --- src/Entities/ItemFrame.cpp | 1 - src/Items/ItemHandler.h | 2 +- src/WorldStorage/NBTChunkSerializer.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp index f0b0c8c65..0bc10ec60 100644 --- a/src/Entities/ItemFrame.cpp +++ b/src/Entities/ItemFrame.cpp @@ -55,7 +55,6 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI) { if (m_Item.IsEmpty()) { - SetHealth(0); super::KilledBy(a_TDI); Destroy(); return; diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 8b554ee34..67c250a97 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -75,7 +75,7 @@ public: int FoodLevel; double Saturation; - FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) : + FoodInfo(int a_FoodLevel, double a_Saturation) : FoodLevel(a_FoodLevel), Saturation(a_Saturation) { diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e435a1b1f..68e541eba 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -615,7 +615,6 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) { m_Writer.BeginCompound(""); AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName()); - Vector3d Pos = a_Projectile->GetPosition(); m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0); switch (a_Projectile->GetProjectileKind()) From 21ff1d81ab4e68f31874894a1f4b7feb53d210df Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:44:10 +0100 Subject: [PATCH 291/751] Improved explosion damage --- src/ChunkMap.cpp | 69 ++++++++++++++++-------------------------------- src/World.cpp | 9 ++++--- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dd8be0631..8ca61e2cf 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1880,21 +1880,18 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { - if (!cBlockInfo::FullyOccupiesVoxel(Block)) + if ( + ((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) || + ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL))) + ) { - break; + m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } - else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL))) - { - break; - } - m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); - break; - + break; } } // switch (BlockType) } // for z @@ -1916,51 +1913,31 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ virtual bool Item(cEntity * a_Entity) override { - if (a_Entity->IsPickup()) + if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20)) { - if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + return false; + } + + Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos; + + if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible + { + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa! { return false; } - } - Vector3d EntityPos = a_Entity->GetPosition(); - cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - - if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround - { - return false; - } - - Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z)); - - // Work out how far we are from the edge of the TNT's explosive effect - AbsoluteEntityPos -= m_ExplosionPos; - - // All to positive - AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x); - AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y); - AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z); - - double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize; - - // Clip damage values - FinalDamage = Clamp(FinalDamage, 0.0, (double)a_Entity->GetMaxHealth()); - - if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible - { - a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); + // Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit + a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0); } // Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() - Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos; - if (distance_explosion.SqrLength() < 4096.0) - { - distance_explosion.Normalize(); - distance_explosion *= m_ExplosionSize * m_ExplosionSize; - - a_Entity->AddSpeed(distance_explosion); - } + DistanceFromExplosion.Normalize(); + DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize; + a_Entity->AddSpeed(DistanceFromExplosion); return false; } diff --git a/src/World.cpp b/src/World.cpp index d2213d1e5..c850c50d3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1188,24 +1188,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo return; } - // TODO: Add damage to entities and implement block hardiness + // TODO: Implement block hardiness Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ); cVector3iArray BlocksAffected; m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected); BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f); + { cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if (ch == NULL) { continue; } + Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos; if (distance_explosion.SqrLength() < 4096.0) { - double real_distance = std::max(0.004, sqrt(distance_explosion.SqrLength())); + double real_distance = std::max(0.004, distance_explosion.Length()); double power = a_ExplosionSize / real_distance; if (power <= 1) { @@ -1217,6 +1219,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo } } } + cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData); } From 618741f78e2e840552663590fd0d6eab03aa874e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 14:43:49 +0100 Subject: [PATCH 292/751] Added new console command with cleanup --- src/Root.cpp | 14 +++--------- src/Server.cpp | 59 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/Root.cpp b/src/Root.cpp index c20cf0d21..f72f0bae3 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -462,16 +462,6 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd) { - // Some commands are built-in: - if (a_Cmd == "stop") - { - m_bStop = true; - } - else if (a_Cmd == "restart") - { - m_bRestart = true; - } - // Put the command into a queue (Alleviates FS #363): cCSLock Lock(m_CSPendingCommands); m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback)); @@ -483,14 +473,16 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd) void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output) { - // Some commands are built-in: + // cRoot handles stopping and restarting due to our access to controlling variables if (a_Cmd == "stop") { m_bStop = true; + return; } else if (a_Cmd == "restart") { m_bRestart = true; + return; } LOG("Executing console command: \"%s\"", a_Cmd.c_str()); diff --git a/src/Server.cpp b/src/Server.cpp index 42ad133f1..4524ece76 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -457,33 +457,34 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac return; } - // Special handling: "stop" and "restart" are built in - if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) - { - return; - } + // "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables // "help" and "reload" are to be handled by MCS, so that they work no matter what if (split[0] == "help") { PrintHelp(split, a_Output); + a_Output.Finished(); return; } if (split[0] == "reload") { cPluginManager::Get()->ReloadPlugins(); cRoot::Get()->ReloadGroups(); + a_Output.Out("Plugins and groups reloaded"); + a_Output.Finished(); return; } if (split[0] == "reloadplugins") { cPluginManager::Get()->ReloadPlugins(); + a_Output.Out("Plugins reloaded"); + a_Output.Finished(); return; } if (split[0] == "reloadgroups") { cRoot::Get()->ReloadGroups(); - a_Output.Out("Groups reloaded!"); + a_Output.Out("Groups reloaded"); a_Output.Finished(); return; } @@ -491,31 +492,54 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { if (split.size() > 1) { - cPluginManager::Get()->LoadPlugin(split[1]); - - return; + a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin"); } else { - a_Output.Out("No plugin given! Command: load "); - a_Output.Finished(); - return; + a_Output.Out("Usage: load "); } + a_Output.Finished(); + return; } - if (split[0] == "unload") { if (split.size() > 1) { cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1])); - return; + a_Output.Out("Plugin unloaded"); } else { - a_Output.Out("No plugin given! Command: unload "); - a_Output.Finished(); - return; + a_Output.Out("Usage: unload "); } + a_Output.Finished(); + return; + } + if (split[0] == "destroyentities") + { + class WorldCallback : public cWorldListCallback + { + virtual bool Item(cWorld * a_World) override + { + class EntityCallback : public cEntityCallback + { + virtual bool Item(cEntity * a_Entity) override + { + if (!a_Entity->IsPlayer()) + { + a_Entity->Destroy(); + } + return false; + } + } EC; + a_World->ForEachEntity(EC); + return false; + } + } WC; + cRoot::Get()->ForEachWorld(WC); + a_Output.Out("Destroyed all entities"); + a_Output.Finished(); + return; } // There is currently no way a plugin can do these (and probably won't ever be): @@ -610,6 +634,7 @@ void cServer::BindBuiltInConsoleCommands(void) PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics"); PlgMgr->BindConsoleCommand("load ", NULL, " - Adds and enables the specified plugin"); PlgMgr->BindConsoleCommand("unload ", NULL, " - Disables the specified plugin"); + PlgMgr->BindConsoleCommand("destroyentities", NULL, " - Destroys all entities in all worlds"); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml"); From 389614c9599dc6a24a0f22b0a16e8af02e4b4cca Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 15:12:45 +0100 Subject: [PATCH 293/751] A better hotfix for CraftingRecipies --- src/CraftingRecipes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 223184c64..ed3409207 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -367,7 +367,7 @@ void cCraftingRecipes::ClearRecipes(void) void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine) { AString RecipeLine(a_RecipeLine); - RecipeLine.erase(std::remove(RecipeLine.begin(), RecipeLine.end(), ' '), RecipeLine.end()); + RecipeLine.erase(std::remove_if(RecipeLine.begin(), RecipeLine.end(), isspace), RecipeLine.end()); AStringVector Sides = StringSplit(RecipeLine, "="); if (Sides.size() != 2) From 9c1fadd50cc935615bb776919ef1ff0587f2590b Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 15:13:47 +0100 Subject: [PATCH 294/751] Updated Core --- MCServer/Plugins/Core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core index 7cc99285a..bd23915df 160000 --- a/MCServer/Plugins/Core +++ b/MCServer/Plugins/Core @@ -1 +1 @@ -Subproject commit 7cc99285ae5117418f657c3b295ca71f2b75b4f4 +Subproject commit bd23915df763b182610c6163c5ff2d64a0756560 From 22e3bbd0db71f9bd6d0a4306db1127f257bd24b1 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 19:19:27 +0300 Subject: [PATCH 295/751] 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 75e131638616c68d126eb64abdf903a93dd7322f Mon Sep 17 00:00:00 2001 From: LO1ZB Date: Fri, 29 Aug 2014 20:19:45 +0200 Subject: [PATCH 296/751] fix chunk regenerating --- src/Generating/ChunkGenerator.cpp | 8 -------- src/World.cpp | 8 ++++++++ src/World.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 4d0cf3192..a1c3d50cc 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -245,14 +245,6 @@ void cChunkGenerator::Execute(void) LastReportTick = clock(); } - // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if (m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) - { - LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); - // Already generated, ignore request - continue; - } - if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); diff --git a/src/World.cpp b/src/World.cpp index eba3a8357..aba5bd859 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2909,7 +2909,15 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) { + if (!(m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkZ))) + { + LOGD("Chunk [%d, %d] already generated, skipping generation", a_ChunkX, a_ChunkZ); + // Already generated, ignore reques + } + else + { m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ); + } } diff --git a/src/World.h b/src/World.h index 50b157312..49e30694e 100644 --- a/src/World.h +++ b/src/World.h @@ -380,7 +380,7 @@ public: /** Regenerate the given chunk: */ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /** Generates the given chunk, if not already generated */ + /** Generates the given chunk */ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export /** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */ From e45a27add934dcdad8eadcea16ce647fb87fbf9d Mon Sep 17 00:00:00 2001 From: LO1ZB Date: Fri, 29 Aug 2014 20:26:19 +0200 Subject: [PATCH 297/751] add comments --- src/World.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/World.cpp b/src/World.cpp index aba5bd859..7c6a1af2f 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2909,10 +2909,11 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) { + /** Add a chunk to the generation queue, if it's not already present. */ if (!(m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkZ))) { LOGD("Chunk [%d, %d] already generated, skipping generation", a_ChunkX, a_ChunkZ); - // Already generated, ignore reques + /** Already generated, ignore reques */ } else { From 5a6ef8b8e5887a13b252623a584ac05f0b2bd070 Mon Sep 17 00:00:00 2001 From: LO1ZB Date: Fri, 29 Aug 2014 20:27:58 +0200 Subject: [PATCH 298/751] me being stupid --- src/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/World.cpp b/src/World.cpp index 7c6a1af2f..f6fed53ee 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2913,7 +2913,7 @@ void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) if (!(m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkZ))) { LOGD("Chunk [%d, %d] already generated, skipping generation", a_ChunkX, a_ChunkZ); - /** Already generated, ignore reques */ + /** Already generated, ignore request */ } else { From a2bee74a13989f725e8f8ca3ffe967e157f8d77f Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 29 Aug 2014 23:21:58 +0300 Subject: [PATCH 299/751] 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); From 4900645b2838b8a953fba298c5001b4e2d242931 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Sat, 30 Aug 2014 00:27:33 +0200 Subject: [PATCH 300/751] Added a_Digger check --- src/Blocks/BlockHandler.cpp | 59 +++++++++++++++++++------------------ src/Entities/Entity.cpp | 4 +-- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index c8a57906f..feb024b7f 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -433,38 +433,41 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac else { // TODO: Add a proper overridable function for this - cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments; - if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer()) + if (a_Digger != NULL) { - switch (m_BlockType) + cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments; + if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer()) { - case E_BLOCK_CAKE: - case E_BLOCK_CARROTS: - case E_BLOCK_COCOA_POD: - case E_BLOCK_DOUBLE_STONE_SLAB: - case E_BLOCK_DOUBLE_WOODEN_SLAB: - case E_BLOCK_FIRE: - case E_BLOCK_FARMLAND: - case E_BLOCK_MELON_STEM: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_NETHER_WART: - case E_BLOCK_POTATOES: - case E_BLOCK_PUMPKIN_STEM: - case E_BLOCK_SNOW: - case E_BLOCK_SUGARCANE: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_CROPS: + switch (m_BlockType) { - // Silktouch can't be used for this blocks - ConvertToPickups(Pickups, Meta); - break; - }; - default: Pickups.Add(m_BlockType, 1, Meta); + case E_BLOCK_CAKE: + case E_BLOCK_CARROTS: + case E_BLOCK_COCOA_POD: + case E_BLOCK_DOUBLE_STONE_SLAB: + case E_BLOCK_DOUBLE_WOODEN_SLAB: + case E_BLOCK_FIRE: + case E_BLOCK_FARMLAND: + case E_BLOCK_MELON_STEM: + case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_NETHER_WART: + case E_BLOCK_POTATOES: + case E_BLOCK_PUMPKIN_STEM: + case E_BLOCK_SNOW: + case E_BLOCK_SUGARCANE: + case E_BLOCK_TALL_GRASS: + case E_BLOCK_CROPS: + { + // Silktouch can't be used for this blocks + ConvertToPickups(Pickups, Meta); + break; + }; + default: Pickups.Add(m_BlockType, 1, Meta); + } + } + else + { + Pickups.Add(m_BlockType, 1, Meta); } - } - else - { - Pickups.Add(m_BlockType, 1, Meta); } } } diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 760401cc2..10a0f8920 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -400,9 +400,9 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) { cItem Item = ArmorItems[i]; - if (Item.m_Enchantments.GetLevel(cEnchantments::enchThorns) > ThornsLevel) ThornsLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchThorns); + ThornsLevel = std::max(ThornsLevel, Item.m_Enchantments.GetLevel(cEnchantments::enchThorns)); } - + if (ThornsLevel > 0) { int Chance = ThornsLevel * 15; From ac95173e81028856e7dac7e751c9526d0c9d4c8a Mon Sep 17 00:00:00 2001 From: LO1ZB Date: Sat, 30 Aug 2014 00:45:05 +0200 Subject: [PATCH 301/751] remove orphaned comment. --- src/ChunkDef.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ChunkDef.h b/src/ChunkDef.h index b7122efe2..111e081db 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -16,10 +16,6 @@ -/** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord. -It will help us when the new chunk format comes out and we need to patch everything up for compatibility. -*/ - // Used to smoothly convert to new axis ordering. One will be removed when deemed stable. #define AXIS_ORDER_YZX 1 // Original (1.1-) #define AXIS_ORDER_XZY 2 // New (1.2+) From d7ee2245e89ce9e71f0172d5a0edf605060bcf2a Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 12:44:54 +0200 Subject: [PATCH 302/751] Added SetWalkSpeed() to cMonster. --- src/Mobs/Monster.cpp | 4 ++++ src/Mobs/Monster.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index f7ee0b0c0..09a22cd35 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -89,6 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString , m_DropChanceBoots(0.085f) , m_CanPickUpLoot(true) , m_BurnsInDaylight(false) + , m_WalkSpeed(1.0) { if (!a_ConfigName.empty()) { @@ -302,6 +303,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) Distance *= 0.25f; } + // Apply walk speed: + Distance *= m_WalkSpeed; + AddSpeedX(Distance.x); AddSpeedZ(Distance.z); diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index cdbd26c09..6db8435e2 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -138,6 +138,9 @@ public: /// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; } + double GetWalkSpeed(void) const { return m_WalkSpeed; } // tolua_export + void SetWalkSpeed(double a_WalkSpeed) { m_WalkSpeed = a_WalkSpeed; } // tolua_export + // Overridables to handle ageable mobs virtual bool IsBaby (void) const { return false; } virtual bool IsTame (void) const { return false; } @@ -248,6 +251,8 @@ protected: void HandleDaylightBurning(cChunk & a_Chunk); bool m_BurnsInDaylight; + double m_WalkSpeed; + /** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/ void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0); From 003206b1b038f4616d5318068106573cec4d4ecd Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 12:45:39 +0200 Subject: [PATCH 303/751] Added slowness effect and added entity support. --- src/Entities/EntityEffect.cpp | 79 +++++++++++++++++++++++++++-------- src/Entities/EntityEffect.h | 4 ++ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp index 58b76b21b..9cf20095d 100644 --- a/src/Entities/EntityEffect.cpp +++ b/src/Entities/EntityEffect.cpp @@ -237,17 +237,18 @@ void cEntityEffect::OnTick(cPawn & a_Target) void cEntityEffectSpeed::OnActivate(cPawn & a_Target) { - // TODO: Add SetMormalMaxSpeed to cMonster - - if (!a_Target.IsPlayer()) + if (a_Target.IsMob()) { - return; + cMonster * Mob = (cMonster*) &a_Target; + Mob->SetWalkSpeed(Mob->GetWalkSpeed() + 0.2 * m_Intensity); + } + else if (a_Target.IsPlayer()) + { + cPlayer * Player = (cPlayer*) &a_Target; + Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.2 * m_Intensity); + Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.26 * m_Intensity); + Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.2 * m_Intensity); } - cPlayer * Player = (cPlayer*) &a_Target; - - Player->SetNormalMaxSpeed(1.0 + 0.2 * m_Intensity); - Player->SetSprintingMaxSpeed(1.3 + 0.26 * m_Intensity); - Player->SetFlyingMaxSpeed(1.0 + 0.2 * m_Intensity); } @@ -256,17 +257,61 @@ void cEntityEffectSpeed::OnActivate(cPawn & a_Target) void cEntityEffectSpeed::OnDeactivate(cPawn & a_Target) { - // TODO: Add SetMormalMaxSpeed to cMonster - - if (!a_Target.IsPlayer()) + if (a_Target.IsMob()) { - return; + cMonster * Mob = (cMonster*) &a_Target; + Mob->SetWalkSpeed(Mob->GetWalkSpeed() - 0.2 * m_Intensity); } - cPlayer * Player = (cPlayer*) &a_Target; + else if (a_Target.IsPlayer()) + { + cPlayer * Player = (cPlayer*) &a_Target; + Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.2 * m_Intensity); + Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.26 * m_Intensity); + Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.2 * m_Intensity); + } +} - Player->SetNormalMaxSpeed(1.0); - Player->SetSprintingMaxSpeed(1.3); - Player->SetFlyingMaxSpeed(1.0); + + + + +//////////////////////////////////////////////////////////////////////////////// +// cEntityEffectSlowness: + +void cEntityEffectSlowness::OnActivate(cPawn & a_Target) +{ + if (a_Target.IsMob()) + { + cMonster * Mob = (cMonster*) &a_Target; + Mob->SetWalkSpeed(Mob->GetWalkSpeed() - 0.15 * m_Intensity); + } + else if (a_Target.IsPlayer()) + { + cPlayer * Player = (cPlayer*) &a_Target; + Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.15 * m_Intensity); + Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.195 * m_Intensity); + Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.15 * m_Intensity); + } +} + + + + + +void cEntityEffectSlowness::OnDeactivate(cPawn & a_Target) +{ + if (a_Target.IsMob()) + { + cMonster * Mob = (cMonster*) &a_Target; + Mob->SetWalkSpeed(Mob->GetWalkSpeed() + 0.15 * m_Intensity); + } + else if (a_Target.IsPlayer()) + { + cPlayer * Player = (cPlayer*) &a_Target; + Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.15 * m_Intensity); + Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.195 * m_Intensity); + Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.15 * m_Intensity); + } } diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h index e123a7f77..7cf9cd3d5 100644 --- a/src/Entities/EntityEffect.h +++ b/src/Entities/EntityEffect.h @@ -156,6 +156,10 @@ public: super(a_Duration, a_Intensity, a_DistanceModifier) { } + + virtual void OnActivate(cPawn & a_Target) override; + + virtual void OnDeactivate(cPawn & a_Target) override; }; From 0fdb1772083d7b4b8dd71c6f084acd9d2e001eec Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 12:46:26 +0200 Subject: [PATCH 304/751] Fixed potion removing in creative mode. --- src/Entities/Player.cpp | 6 ++---- src/Items/ItemGoldenApple.h | 1 + src/Items/ItemHandler.cpp | 1 + src/Items/ItemMilk.h | 8 ++++++-- src/Items/ItemPotion.h | 8 ++++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index b0dd40615..5e0da3298 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -627,13 +627,11 @@ void cPlayer::FinishEating(void) } ItemHandler->OnFoodEaten(m_World, this, &Item); - GetInventory().RemoveOneEquippedItem(); - // if the food is mushroom soup, return a bowl to the inventory if (Item.m_ItemType == E_ITEM_MUSHROOM_SOUP) { - cItem EmptyBowl(E_ITEM_BOWL); - GetInventory().AddItem(EmptyBowl, true, true); + GetInventory().RemoveOneEquippedItem(); + GetInventory().AddItem(cItem(E_ITEM_BOWL), true, true); } } diff --git a/src/Items/ItemGoldenApple.h b/src/Items/ItemGoldenApple.h index 02ac0202c..5f6f1de6c 100644 --- a/src/Items/ItemGoldenApple.h +++ b/src/Items/ItemGoldenApple.h @@ -36,6 +36,7 @@ public: a_Player->AddEntityEffect(cEntityEffect::effFireResistance, 6000, 0); } + a_Player->GetInventory().RemoveOneEquippedItem(); return true; } diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index bceedaf69..ca0f04dcc 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -632,6 +632,7 @@ bool cItemHandler::GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_Eff bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) { UNUSED(a_Item); + a_Player->GetInventory().RemoveOneEquippedItem(); FoodInfo Info = GetFoodInfo(); if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f)) diff --git a/src/Items/ItemMilk.h b/src/Items/ItemMilk.h index db7bc13be..c9a90865a 100644 --- a/src/Items/ItemMilk.h +++ b/src/Items/ItemMilk.h @@ -21,8 +21,12 @@ public: { UNUSED(a_Item); a_Player->ClearEntityEffects(); - a_Player->GetInventory().RemoveOneEquippedItem(); - a_Player->GetInventory().AddItem(E_ITEM_BUCKET); + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_BUCKET); + } return true; } }; diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h index 24614cd8a..398ef6805 100644 --- a/src/Items/ItemPotion.h +++ b/src/Items/ItemPotion.h @@ -68,8 +68,12 @@ public: cEntityEffect::GetPotionEffectDuration(PotionDamage), cEntityEffect::GetPotionEffectIntensity(PotionDamage) ); - a_Player->GetInventory().RemoveOneEquippedItem(); - a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE); + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE); + } return true; } }; From 04653b45394a9e95fddcae274cca0c422f21cfdc Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 12:53:19 +0200 Subject: [PATCH 305/751] Added GetWalkSpeed() and SetWalkSpeed() documentation. --- MCServer/Plugins/APIDump/APIDesc.lua | 2 ++ MCServer/Plugins/SexyMotd | 1 + 2 files changed, 3 insertions(+) create mode 120000 MCServer/Plugins/SexyMotd diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 3e1a6e3bb..434dd8a90 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1636,6 +1636,8 @@ a_Player:OpenWindow(Window); MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." }, MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" }, StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." }, + GetWalkSpeed = { Params = "", Return = "number", Notes = "Returns the walk speed of this mob. Standard is 1.0" }, + SetWalkSpeed = { Params = "number", Return = "", Notes = "Sets the walk speed of this mob. Standard is 1.0" }, }, Constants = { diff --git a/MCServer/Plugins/SexyMotd b/MCServer/Plugins/SexyMotd new file mode 120000 index 000000000..b6af08265 --- /dev/null +++ b/MCServer/Plugins/SexyMotd @@ -0,0 +1 @@ +/home/franz/Schreibtisch/MCServer Plugins/SexyMotd/ \ No newline at end of file From c5be3e0b6673c03c9a4dba109454af8bcaefc4e5 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 12:55:43 +0200 Subject: [PATCH 306/751] Removed SexyMotd link --- MCServer/Plugins/SexyMotd | 1 - 1 file changed, 1 deletion(-) delete mode 120000 MCServer/Plugins/SexyMotd diff --git a/MCServer/Plugins/SexyMotd b/MCServer/Plugins/SexyMotd deleted file mode 120000 index b6af08265..000000000 --- a/MCServer/Plugins/SexyMotd +++ /dev/null @@ -1 +0,0 @@ -/home/franz/Schreibtisch/MCServer Plugins/SexyMotd/ \ No newline at end of file From 3ee3a59e75ac1e6eb9284983a05a459aab5be1fd Mon Sep 17 00:00:00 2001 From: Howaner Date: Sat, 30 Aug 2014 15:06:43 +0200 Subject: [PATCH 307/751] Changed the IsEnchantable() comment. --- MCServer/Plugins/APIDump/APIDesc.lua | 2 +- src/Item.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index d75911666..da8f9cd74 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1209,7 +1209,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins, IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." }, GetEnchantability = { Params = "", Return = "number", Notes = "Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0" }, EnchantByXPLevels = { Params = "NumXPLevels", Return = "bool", Notes = "Enchants the item using the specified number of XP levels. Returns true if item enchanted, false if not." }, - IsEnchantable = { Params = "ItemType, WithBook", Return = "bool", Notes = "(STATIC) Returns true if the specified item type is enchantable." }, + IsEnchantable = { Params = "ItemType, WithBook", Return = "bool", Notes = "(STATIC) Returns true if the specified item type is enchantable. If WithBook is true, the function checks the enchantments with a book too." }, }, Variables = { diff --git a/src/Item.h b/src/Item.h index 316928b9e..e7fd67b9a 100644 --- a/src/Item.h +++ b/src/Item.h @@ -183,7 +183,8 @@ public: /** Loads the item data from JSON representation */ void FromJson(const Json::Value & a_Value); - /** Returns true if the specified item type is enchantable. */ + /** Returns true if the specified item type is enchantable. + If WithBook is true, the function checks the enchantments with a book too. */ static bool IsEnchantable(short a_ItemType, bool a_WithBook = false); // tolua_export /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */ From 55907376d5806415fe60b933ed076efc505e2f83 Mon Sep 17 00:00:00 2001 From: Masy98 Date: Sat, 30 Aug 2014 21:36:20 +0200 Subject: [PATCH 308/751] Fixed missing slab name in line 297 --- MCServer/items.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MCServer/items.ini b/MCServer/items.ini index d3ae721f3..4f4df220e 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -294,7 +294,7 @@ bigoakwooddoubleslab=125:5 darkoakwooddoubleslab=125:5 roofedwooddoubleslab=125:5 woodenslab=126 -applewood=126:0 +applewoodslab=126:0 oakwoodslab=126:0 coniferwoodslab=126:1 pinewoodslab=126:1 From b0a7d93ae1b3de1a6c14caf30f26682108b4a6b7 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 30 Aug 2014 22:11:09 +0200 Subject: [PATCH 309/751] Fixed MSVC2008 compilation. It was getting confused about which sqrt() overload to call. --- src/Entities/Minecart.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 21c58fdba..1501eea84 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -891,31 +891,31 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) ) { // Moving -X +Z - if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01) + if ((-GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01) { // ~ SpeedX >= 0 Immobile or not moving in the "right" direction. Give it a bump! - AddSpeedX(-4 / sqrt(2)); - AddSpeedZ(4 / sqrt(2)); + AddSpeedX(-4 / sqrt(2.0)); + AddSpeedZ(4 / sqrt(2.0)); } 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)); + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0)); } } - else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01) + else if ((GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01) { // Moving +X -Z // ~ SpeedX <= 0 Immobile or not moving in the "right" direction - AddSpeedX(4 / sqrt(2)); - AddSpeedZ(-4 / sqrt(2)); + AddSpeedX(4 / sqrt(2.0)); + AddSpeedZ(-4 / sqrt(2.0)); } else { // ~ SpeedX > 0 Moving in the "right" direction - SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); - SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0)); } break; } @@ -943,28 +943,28 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) if ((GetSpeedX() * 0.4) < 0.01) { // ~ SpeedX <= 0 Immobile or not moving in the "right" direction - AddSpeedX(4 / sqrt(2)); - AddSpeedZ(4 / sqrt(2)); + AddSpeedX(4 / sqrt(2.0)); + AddSpeedZ(4 / sqrt(2.0)); } else { // ~ SpeedX > 0 Moving in the "right" direction - SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); - SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0)); } } 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)); + AddSpeedX(-4 / sqrt(2.0)); + AddSpeedZ(-4 / sqrt(2.0)); } else { // ~ SpeedX < 0 Moving in the "right" direction - SetSpeedX(GetSpeedX() * 0.4 / sqrt(2)); - SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2)); + SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0)); + SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0)); } break; } From fc7da227386a1788a8b6ddaeb5ae5b52fde107be Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 30 Aug 2014 22:11:52 +0200 Subject: [PATCH 310/751] WSSAnvil: Removed leftover debugging code. --- src/WorldStorage/WSSAnvil.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 5978e5ef8..e79cc291d 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -592,10 +592,6 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con } 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); From db663c7ee1737f5e03c0bce6584933123b9d58e3 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 30 Aug 2014 22:24:04 +0200 Subject: [PATCH 311/751] Fixed style. --- src/BlockEntities/CommandBlockEntity.cpp | 5 +++-- src/ChunkMap.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index fe2f5e60a..dd0858378 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -211,13 +211,14 @@ void cCommandBlockEntity::Execute() } } CmdBlockOutCb(this); - if ( // Administrator commands are not executable by command blocks + // Administrator commands are not executable by command blocks: + if ( (m_Command != "stop") && (m_Command != "restart") && (m_Command != "kick") && (m_Command != "ban") && (m_Command != "ipban") - ) + ) { cServer * Server = cRoot::Get()->GetServer(); LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 8ca61e2cf..a3692ef11 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1880,10 +1880,11 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { + // If the block is shrapnel-able, make a falling block entity out of it: if ( ((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) || ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL))) - ) + ) { m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } @@ -1891,7 +1892,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); - break; + break; } } // switch (BlockType) } // for z From 365d2447d002747c0f43471e0d3bf42ea9d21363 Mon Sep 17 00:00:00 2001 From: worktycho Date: Sun, 31 Aug 2014 00:15:48 +0100 Subject: [PATCH 312/751] Check range of y in HasNearLog Fixes #803 --- src/Blocks/BlockLeaves.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 972dd6232..a8aa28a0f 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -152,7 +152,7 @@ bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ) a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE); for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) { - for (int y = a_BlockY - i; y <= a_BlockY + i; y++) + for (int y = std::max(a_BlockY - i, 0); y <= std::min(a_BlockY + i, 255); y++) { for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++) { From 6180f7df095c228530e4c0d2bfaa90fed7b11f49 Mon Sep 17 00:00:00 2001 From: Jaume Aloy Date: Sun, 31 Aug 2014 11:28:42 +0200 Subject: [PATCH 313/751] Fixed style --- src/Entities/Entity.cpp | 12 +++++------- src/Entities/Player.cpp | 3 +++ src/Entities/ProjectileEntity.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 10a0f8920..e36ed6c37 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -396,7 +396,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) } int ThornsLevel = 0; - cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; + const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) { cItem Item = ArmorItems[i]; @@ -428,7 +428,8 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); } - if (IsPlayer()){ + if (IsPlayer()) + { double TotalEPF = 0.0; double EPFProtection = 0.00; double EPFFireProtection = 0.00; @@ -436,7 +437,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) double EPFProjectileProtection = 0.00; double EPFFeatherFalling = 0.00; - cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; + const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) { cItem Item = ArmorItems[i]; @@ -469,7 +470,6 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) TotalEPF = EPFProtection + EPFFireProtection + EPFFeatherFalling + EPFBlastProtection + EPFProjectileProtection; - EPFProtection = EPFProtection / TotalEPF; EPFFireProtection = EPFFireProtection / TotalEPF; EPFFeatherFalling = EPFFeatherFalling / TotalEPF; @@ -507,8 +507,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) a_TDI.FinalDamage -= RemovedDamage; } - - + m_Health -= (short)a_TDI.FinalDamage; @@ -516,7 +515,6 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = std::max(m_Health, 0); - if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs { int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 8b829d090..338a87ac1 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1963,6 +1963,8 @@ void cPlayer::UseEquippedItem(int a_Amount) { return; } + + // If the item has an unbreaking enchantment, give it a random chance of not breaking: cItem Item = GetEquippedItem(); int UnbreakingLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking); if (UnbreakingLevel > 0) @@ -1983,6 +1985,7 @@ void cPlayer::UseEquippedItem(int a_Amount) return; } } + if (GetInventory().DamageEquippedItem(a_Amount)) { m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 58dc38702..990136a32 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -94,7 +94,7 @@ protected: */ struct CreatorData { - CreatorData(int a_UniqueID, const AString & a_Name, cEnchantments a_Enchantments) : + CreatorData(int a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) : m_UniqueID(a_UniqueID), m_Name(a_Name), m_Enchantments(a_Enchantments) From 7e5f22141f72fd1ad0ec7982df03f126e9c11244 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 31 Aug 2014 12:59:04 +0200 Subject: [PATCH 314/751] WebAdmin: Added "files" folder and load the login template from login_template.html --- src/WebAdmin.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++----- src/WebAdmin.h | 6 +++ 2 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index 23eedbd14..0646c9d1c 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -135,6 +135,20 @@ bool cWebAdmin::Start(void) m_TemplateScript.Close(); } + if (!LoadLoginTemplate()) + { + LOGWARN("Could not load WebAdmin login template \"%s\", using fallback template.", FILE_IO_PREFIX "webadmin/login_template.html"); + + // Sets the fallback template: + m_LoginTemplate = \ + "

MCServer WebAdmin

" \ + "
" \ + "
" \ + "" \ + "
" \ + "
"; + } + m_IsRunning = m_HTTPServer.Start(*this); return m_IsRunning; } @@ -159,6 +173,28 @@ void cWebAdmin::Stop(void) +bool cWebAdmin::LoadLoginTemplate(void) +{ + cFile File(FILE_IO_PREFIX "webadmin/login_template.html", cFile::fmRead); + if (!File.IsOpen()) + { + return false; + } + + AString TemplateContent; + if (File.ReadRestOfFile(TemplateContent) == -1) + { + return false; + } + + m_LoginTemplate = TemplateContent; + return true; +} + + + + + void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { if (!a_Request.HasAuth()) @@ -298,17 +334,11 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque void cWebAdmin::HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { UNUSED(a_Request); - static const char LoginForm[] = \ - "

MCServer WebAdmin

" \ - "
" \ - "
" \ - "" \ - "
" \ - "
"; + cHTTPResponse Resp; Resp.SetContentType("text/html"); a_Connection.Send(Resp); - a_Connection.Send(LoginForm, sizeof(LoginForm) - 1); + a_Connection.Send(m_LoginTemplate); a_Connection.FinishResponse(); } @@ -528,7 +558,64 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & } else { - // TODO: Handle other requests + AString FileURL = URL; + std::replace(FileURL.begin(), FileURL.end(), '\\', '/'); + + // Remove all backsplashes on the first place: + if (FileURL[0] == '/') + { + size_t FirstCharToRead = FileURL.find_first_not_of('/'); + if (FirstCharToRead != AString::npos) + { + FileURL = FileURL.substr(FirstCharToRead); + } + } + + // Remove all "../" strings: + ReplaceString(FileURL, "../", ""); + + bool LoadedSuccessfull = false; + AString Content = "

404 Not Found

"; + AString Path = Printf(FILE_IO_PREFIX "webadmin/files/%s", FileURL.c_str()); + if (cFile::IsFile(Path)) + { + cFile File(Path, cFile::fmRead); + AString FileContent; + if (File.IsOpen() && (File.ReadRestOfFile(FileContent) != -1)) + { + LoadedSuccessfull = true; + Content = FileContent; + } + } + + // Find content type (The currently method is very bad. We should change it later) + AString ContentType = "text/html"; + size_t LastPointPosition = Path.find_last_of('.'); + if (LoadedSuccessfull && (LastPointPosition != AString::npos) && (LastPointPosition < Path.length())) + { + const AString & FileExtension = StrToLower(Path.substr(LastPointPosition + 1)); + if (FileExtension == "png") ContentType = "image/png"; + if (FileExtension == "fif") ContentType = "image/fif"; + if (FileExtension == "gif") ContentType = "image/gif"; + if (FileExtension == "jpeg") ContentType = "image/jpeg"; + if (FileExtension == "jpg") ContentType = "image/jpeg"; + if (FileExtension == "jpe") ContentType = "image/jpeg"; + if (FileExtension == "tiff") ContentType = "image/tiff"; + if (FileExtension == "ico") ContentType = "image/ico"; + if (FileExtension == "csv") ContentType = "text/comma-separated-values"; + if (FileExtension == "css") ContentType = "text/css"; + if (FileExtension == "js") ContentType = "text/javascript"; + if (FileExtension == "txt") ContentType = "text/plain"; + if (FileExtension == "rtx") ContentType = "text/richtext"; + if (FileExtension == "xml") ContentType = "text/xml"; + } + + // Send the response: + cHTTPResponse Resp; + Resp.SetContentType(ContentType); + a_Connection.Send(Resp); + a_Connection.Send(Content); + a_Connection.FinishResponse(); } // Delete any request data assigned to the request: @@ -551,4 +638,3 @@ void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, size_t a_Size) - diff --git a/src/WebAdmin.h b/src/WebAdmin.h index aefc1d145..a59c69096 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -116,6 +116,9 @@ public: /** Stops the HTTP server, if it was started. */ void Stop(void); + /** Loads the login template. Returns true if the loading success, false if not. */ + bool LoadLoginTemplate(void); + void AddPlugin(cWebPlugin * a_Plugin); void RemovePlugin(cWebPlugin * a_Plugin); @@ -205,6 +208,9 @@ protected: /** The Lua template script to provide templates: */ cLuaState m_TemplateScript; + /** The template who provide the login side: */ + AString m_LoginTemplate; + /** The HTTP server which provides the underlying HTTP parsing, serialization and events */ cHTTPServer m_HTTPServer; From 8934ab487e92d070301617298b3856cddafab643 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 31 Aug 2014 14:20:42 +0200 Subject: [PATCH 315/751] WebAdmin: Added login template --- MCServer/webadmin/files/mc-logo.png | Bin 0 -> 66137 bytes MCServer/webadmin/login_template.html | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 MCServer/webadmin/files/mc-logo.png create mode 100644 MCServer/webadmin/login_template.html diff --git a/MCServer/webadmin/files/mc-logo.png b/MCServer/webadmin/files/mc-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9a77a490f773a862299c1db7c334a2fb9fa86ddc GIT binary patch literal 66137 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 + + MCServer WebAdmin - Login + + + + + +

+ +

MCServer - WebAdmin

+
+ +
+
+ + + From 9a95b006488e2813cf5f7fc73c5bff1b2fb54964 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 31 Aug 2014 14:39:58 +0200 Subject: [PATCH 316/751] WebAdmin: Exported stylesheet in a own file. --- MCServer/webadmin/files/style.css | 326 +++++++++++++++++++++++++++++ MCServer/webadmin/template.lua | 336 +----------------------------- 2 files changed, 329 insertions(+), 333 deletions(-) create mode 100644 MCServer/webadmin/files/style.css diff --git a/MCServer/webadmin/files/style.css b/MCServer/webadmin/files/style.css new file mode 100644 index 000000000..044204084 --- /dev/null +++ b/MCServer/webadmin/files/style.css @@ -0,0 +1,326 @@ +/* reset CSS */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: transparent; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} + +/* remember to define focus styles! */ +:focus { + outline: 0; +} + +/* remove textarea resize at Safari */ +textarea { + resize: none; +} + +/* remember to highlight inserts somehow! */ +ins { + text-decoration: none; +} +del { + text-decoration: line-through; +} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: collapse; + border-spacing: 0; +} + + +/* + Origional from http://www.perspectived.com/ + Modified by Ben Phelps + Made for FakeTruth - MCServer +*/ + +/* Basic ---------------------------------------- */ + +.clear { clear: both; } + +body { + background: white; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + color: #646464; + text-align: center; +} + +#wrapper { + text-align: left; + width: 930px; + margin: 0 auto; +} + +/* Logo ---------------------------------------- */ + +h1 { + margin: 15px 0 10px 5px; + width: 180px; + height: 36px; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAAkCAMAAAAXdeBDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuVQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7OzAAAAAAAAoqKiAAAAvLy8AAAAlZWVtbW1j4+Pra2tiYmJp6enAAAAhISEoaGhAAAAgICAm5ube3t7lZWVd3d3kZGRc3NzjIyMbGxsg4ODgICAeHh43NzcdXV1cnJyy8vLWVlZbGxswcHB09PTvLy8uLi4tLS0sLCwvLy8uLi4tbW1oaGhnp6era2tm5ubqqqq39/f29vblZWV09PT4ODgz8/P3NzckZGRxcXF0tLSwsLCzs7Oy8vLyMjIt7e3vLy85ubm7u7u3d3d5+fn2tra5OTk19fX1dXV3t7e29vb2dnZ1tbW0dHRv7+/8PDw7u7u6+vr8fHx5ubm4+Pj7Ozs4eHh3t7e5+fn5OTk2tra4uLi39/f1dXV3d3d29vb2dnZ19fX1dXV0tLS9fX18/Pzzs7O7u7u8/PzycnJ6urq6Ojo7+/v5ubm7Ozs4+Pj4eHh39/f5ubm5OTk4uLi4ODg2NjY3Nzc29vb19fX8vLy9/f39fX17e3t8/Pz6+vr8fHx7+/v5+fn7e3t5eXl6+vr6enp6Ojo4ODg39/f9PT0+Pj48fHx9vb27+/v9PT07e3t8/Pz7Ozs8fHx7+/v6Ojo7u7u5+fn7Ozs5eXl6urq5OTk6enp5+fn5ubm5OTk+Pj49/f39fX19PT0+fn58vLy8fHx9fX19PT08vLy8fHx6urq+Pj49vb29fX19PT08vLy8PDw+/v7+vr6+Pj49/f39vb29fX18/Pz/f39+/v7+vr6+fn5+Pj49/f3/f39/Pz8+vr6/v7+/f39a5KrdZmxf6G2iai8kq/BnLbHpr7NsMXSuszYxNPdxmZTynBeznpqztvj0YV11Y+B2OLp2ZmM3aOY4a2j4enu5Liv6MK66/D07MzG8NbR9ODd9fj59+vo+/X0ucu1kQAAANl0Uk5TAAECAwQFBgcICQoLDA0ODxAREhMUFBUWFhcXGBgYGRkaGhsbGxwcHB0dHh4fHyEhIiQkJSYnKCgpKSorLC0uLzAxMjIzMzc4Ojo6Ozs8Pj4/P0BBQ0VISUtLTExNTk5PUFFTV1dYWVpbXFxdXl5fYGBhYmJjZGVmZ2doaWprbGxtbW5ub3BxcXJzdHV2d3l6e3x9fX5+f4CAgYGCg4SIi4yNjY6Oj4+QkJGSkpOTlJSVlZaXmJqbnJ2dnp+foKGip6+wsbKztb6/wMHCw8TOz9DR0tPf4OHv8LXp8fEAAAi/SURBVHja3Zh/dBRXFcdhZ+a9eTPzZnaXmJam0FYUEQWLrVVbqdZaf6EWQW2txN/SWiAmxFqtIlWr9bdWqkbwF6WQYIq/+WFpwSZqTahhg6RhNptkl9nsbjeb2eyv+dv73g6wlcyewXMazvGek3Dm5jLv8+689733vTn/q81ldr5zzsWxuVWr55sbCAiiBCYKAeZ1nYIgigJ4Zh2Zj+0OXesTgQ987pOEZUVVVYXISIJQPi3mJETG0kXADggIL5CRWDMy57kCaDgdBMgK1de0gi2jGsESZJt5iXpjS8utGkHiLFMDIHrNgfJBFYs1i0Ei73iifIAggIEHrNDWnuGpFFg50vEKVYbcArNye0+lUCj13aUgYbahRbInbqbu1zAf2XXpR8bN1CZZYItA1jb0pcaiJrdYorxzIRYFYN7qZC2wTOVXMuR+dqGR2hU3Y4NLFSlwJtGIfmbKNFOt4BIkQndOj5rR8dMpsETMjCae+gASJbLKSSftUsWeSJbWz3aqgXBvPGomOnWWajfRoWOjAN2uIWBedOh0NJoYPvJgW1tb+47I1Jg5Vl6AsPrkZLLU+f5bdjjpzNOzDo1pdzw2Fi2vVlBVFgRMf5oyYXl8lmIk00MJc7S8e6mhU02jerC5JzFavgyRlztWbl9j2NC3lvJbpMDFgJ6Ojh/VZb4XA5KycmhkNAXQOpG1ncDfv9HQQNsQZsK3cNvTn5SQ0lKwCveEdYWQd25BrugxUQHjAl/fPKL9Q2t747F/x82pjSpXC0Gme+EJoNt1Vb2jHI1FVlMmawFWYiQgB6mWCIcOaVgCA2ZX3BEGQyI4vAsXWN1of9Bd8diJZ0dG+3QiwuSRsq4cHf8rgzao3jMWnX5Al88oMdNnAQRPlOlwMrcvrBMYk2WrWmyIqlGqqYRJPE+kwK2a0Jr8wo9nNPzRL/QvTpupH4HsAQ4DLX+ZQQeNN02b8W6DSLWVh5mA+EbcHaKkWhF5sdGWdfREIj0dyzSCBDAJY1nGCKo/r/9uguEB/uQZLQZ8Qe+JxwZffGx0ZGixgiSsbXzOTDz2RQYdDm1PmFNrNXTee+ZKMpO8fP+DhiYjAGLF5oYux86m01nb6bqBACr+4Id1/cZHH7pUxne+HkE63fp7522A5xn9IiHgF7ppM6DuokRWjD7Av+7zDHrevEgsFgkq0vndnVtcMvmhjkUKJFvEyqf7ckkrmU7Dr1zfXQTLXyoWv95ZydnblB8UKut5BYL/Rw4Uih9S6Qav6B9CnD/oSGPj0fFouVmn+sOwUH7W9DmmHg0Nw9H4Xp0IM1Z/KOOFjDVhR7ZqMpbVO5yMlS2eGhw8VYTJOC9RtOPp9Ak7adk/picnMv/UZL5jyO0ly+4INntGP+QfOhxeXY6O9c4L31QeGettaLyHQTeuKJsALQdm3PyI0Na+UtZKl3ZSjS7uzVr23z7e0Nj00t8Wk2nnZaoeSadtK1s6uJD+xLYKLSBOTJp6sklnxXLP6AOXin6XRyRoGLsS5nObm34HctccCrdz6GsYNJ0JmquFrOjNvcV0srQrFN5tW/bh5aHQvPm/KQHFVkULDsK3n/x7s0bURZDqPtAg+DxrSlau+5JOz2gVCX434nGod4uhpDzzielo/HFdD7bXzbSbbBHJmvEAbMjK5qZTyUz/8qCuhzsZxf0qUUODaSt94n06rB3aYVulZhVLMgXRcd5SL1oM+IamCtEeTpmn/wFyt1JV9ba6a9qlZtgKUE9kjn0vb+W/FdapsYtTaBgrDCP/3bAiQX4XD01ke6B8qisdkPf5364TDcy+oQkmRu/YyGmmITKhbXXVwy10DFtSgjsgjX/KWc41IeMshQj+wTT4dBxg3cx2iGHbvCuXdN58yb560XP8Q8sSUpunzOho/xICX73trE5P33yeTgOre0KDNYLp1Y5l/xkwrm0In6UICMSArTUYVmHGMLNlTjLbGw69chj+aWjorhftHxoECWrh43HoouEluAodNNZMzVQRWQty2wJJ5NRIexU0fAz6tU2dVQomyVUM+ExCtXGspvjnLOGh0N460RcELQQkcn15/AnAFxCHbvPqPUSE9xedKyBDHPpqBm1blXc/5lKwfkRSOIbBNwQ8vQEW8x+uexaWtqEb2z2jLxSaadjb/vJWLAUCLnRtlye4bQ7CYPK7Slb+ayrMhfUqt1Ss/PeLlv17RvFVqsisEcQqx2C7+FyqfwmJXqcp2ke9oi8YGl4tSkgSAM6Fph799KcU7SSkLEgJxoSGYYVW3v5MZqIAFN8I65qqvu6RLUQLcgx4r9ukO0n7X5lsr04w0fu9on1CI5VDY4F/fN5DAnRriq3u2pMLrTm5XKVBjcvvDoPTCO8uJSePzr+3YFlp5ztNDUEjuO6pXP4rtAaDp/rI5ETBKn5MRbDl2zyifUMrDFrFgdoeTuHQyrkz4hCcEcF29PMz4lXKlVAk8r3fXHtzey8rw+8JzTtsW5POH++9dkV7twM1ehtlH/w4K6duqteWLCgphiyyJeUd7cMAkDwK0AQ9D5psAuhN5NxpfMQ9jY/y07gsK6ucSSubL1UKWYttJ5UuBY5kruA4BWjf7IOXqxRaoLPJgK5Dh36j0Mo6EJjBEo9on9AifiQeG8BSLbSA7wbou7HHvYcsSUhZ9aQ9YYFN5CJbVRnJ6pLDxYzFLVM8dDkhykA6PSDDe91UQ39X7fV4i+gZ7ceA6tW/HviCVNumwAh4f3k/ljxvmAQBkSs7TpYKheLQnusVJIIMErqxr1TI5QqVvg0gZAjfNzBwH3Lfy0DJeod31ezBO9qXsfOPexqqnQlagGa8y1MJFqviB85bW1o+QiHNTHEENrn3tnZ1tb6RsmMBkyJUcznJ5PIyyRX8OtF+jEsGG/S/fPyIOdOtKZuf2+NhonAPBLqTI6qmKQTDLPhrmbjXjnPmuW60/wtqryt07/tp3oA8z8MdCHHXjBcC7mOd6Bfk7r3udC94aDf6/9T+AzWzIkAbVeu4AAAAAElFTkSuQmCC) no-repeat left top; +} + +h1 a { + display: block; + width: 225px; + height: 28px; +} + +h1 span { display: none; } + +a { + color: #646464; +} + +/* Container ---------------------------------------- */ + +#containerHolder { + background: #eee; + padding: 5px; +} + + +#container { + background: #fff url(data:image/gif;base64,R0lGODlhtAABAIAAAN3d3f///yH5BAAAAAAALAAAAAC0AAEAAAIMjI+py+0Po5y0WgYKADs%3D) repeat-y left top; + border: 1px solid #ddd; + width: 918px; + +} + +#connectHolder { + background: #eee; + padding: 5px; + margin-bottom:8px; +} + + +#connect { + border: 1px solid #ddd; + background-color: #fff; + padding:5px; + width: 908px; +} + +.pics { + height: 375px; + width: 600px; +} + +.pics img { + padding: 5px; + border: 1px solid #ddd; + background-color: #eee; + width: 600px; + height: 375px; + margin-left: 15px; +} + +/* Login -------------------------------------- */ + +#loginLogo { + margin: 0 auto; + margin-top:100px; + width: 180px; + height: 36px; + background-image: url(data:image/png;base64,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); +} + +#loginHolder { + background: #eee; + padding: 5px; + width: 310px; + margin: 0 auto; + height: 90px; + margin-top:20px; +} + +#login { + padding:10px; + width: 288px; + height: 68px; + border: 1px solid #ddd; + background:#fff; + text-align: left; +} + + +/* Sidebar ---------------------------------------- */ + +#sidebar { + width: 179px; + float: left; +} + +#sidebar .sideNav { width: 179px; } + +#sidebar .sideNav li { border-bottom: 1px solid #ddd; width: 179px; } + +#sidebar .sideNav li a { + display: block; + color: #646464; + background: #f6f6f6; + text-decoration: none; + height: 29px; + line-height: 29px; + padding: 0 19px; + width: 141px; +} + +#sidebar .sideNav li a:hover { background: #fdfcf6; } + +#sidebar .sideNav li a.active, #sidebar .sideNav li a.active:hover { + background: #f0f7fa; + color: #c66653; +} + +/* Breadcrumb ---------------------------------------- */ + +h2 { + width: 718px; + float: right; + color: #646464; + font-size: 16px; + line-height: 16px; + font-weight: bold; + margin: 20px 0 0 0; + padding: 0 0 10px 0; + border-bottom: 1px solid #ddd; +} + +h2 a { + color: #646464; + text-decoration: none; +} + +h2 a.active { color: #c66653; } + +h2 a:hover { text-decoration: underline; } + +/* Content ---------------------------------------- */ + +#main { + width: 700px; + float: right; + padding: 0 19px 0 0; +} + +#main p { + + padding: 10px; + +} + +h3 { + font-size: 14px; + line-height: 14px; + font-weight: bold; + color: #5494af; + padding: 0 0 0 10px; + margin: 20px 0 10px; +} + +h4 { + padding: 0 0 0 10px; + margin: 20px 0 10px; +} + +#main ul { + padding: 0 0 0 10px; + list-style-type: circle; + list-style-position: inside; +} + +#main table { + border-top: 1px solid #ddd; + width: 700px; +} + +#main table tr th { + text-align: left; + background: #f6f6f6; + padding: 0px 20px; + height: 20px; + line-height: 20px; + border-bottom: 1px solid #ddd; +} + +#main table tr td { + background: #f6f6f6; + padding: 0px 20px; + height: 29px; + line-height: 29px; + border-bottom: 1px solid #ddd; +} + +#main table tr.odd td { + background: #fbfbfb; +} + +#main table tr:hover td { background: #fdfcf6; } + +#main table .action { + text-align: right; + padding: 0 20px 0 10px; +} + +#main table tr .action a { margin: 0 0 0 10px; text-decoration: none; color: #9b9b9b; } +#main table tr:hover .action .edit { color: #c5a059; } +#main table tr:hover .action .delete { color: #a02b2b; } +#main table tr:hover .action .view { color: #55a34a; } + +#main table tr:hover .action a:hover { text-decoration: underline; } + +fieldset { + border: 1px solid #ddd; + padding: 19px; + margin: 0 0 20px 0; + background: #fbfbfb; +} + +form p { margin: 0 0 14px 0; float: left; width: 100%; } + +label { + display: block; + width: 100%; + margin: 0 0 7px 0; + line-height: 12px; +} + +/* Footer ---------------------------------------- */ + +#footer { + margin: 10px 0 30px 0; + font-size: 11px; + line-height: 11px; + color: #9B9B9B; + padding: 0 0 0 5px; +} + +#footer a { color: #9B9B9B; } + +#footer a:hover { text-decoration: none; } diff --git a/MCServer/webadmin/template.lua b/MCServer/webadmin/template.lua index a066d8b33..5d5ac7b20 100644 --- a/MCServer/webadmin/template.lua +++ b/MCServer/webadmin/template.lua @@ -57,7 +57,7 @@ end function ShowPage(WebAdmin, TemplateRequest) SiteContent = {} local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path) - local Title = "MCServer" + local Title = "MCServer WebAdmin" local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage() local NumChunks = cRoot:Get():GetTotalChunkCount() local PluginPage = WebAdmin:GetPage(TemplateRequest.Request) @@ -76,337 +76,7 @@ function ShowPage(WebAdmin, TemplateRequest) ]] .. Title .. [[ - - - + @@ -464,4 +134,4 @@ function ShowPage(WebAdmin, TemplateRequest) ]]) return table.concat(SiteContent) -end \ No newline at end of file +end From fca986ec7139100939c3290a5f211d868320510f Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 31 Aug 2014 14:51:07 +0200 Subject: [PATCH 317/751] WebAdmin: Exported favicon. --- MCServer/webadmin/files/favicon.ico | Bin 0 -> 32038 bytes MCServer/webadmin/template.lua | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 MCServer/webadmin/files/favicon.ico diff --git a/MCServer/webadmin/files/favicon.ico b/MCServer/webadmin/files/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ea4bde926a8cc6c0111e712b28a8d4cf92f01372 GIT binary patch literal 32038 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 A_y7O^ literal 0 HcmV?d00001 diff --git a/MCServer/webadmin/template.lua b/MCServer/webadmin/template.lua index 5d5ac7b20..a7480f83e 100644 --- a/MCServer/webadmin/template.lua +++ b/MCServer/webadmin/template.lua @@ -74,7 +74,7 @@ function ShowPage(WebAdmin, TemplateRequest) - + ]] .. Title .. [[ @@ -91,16 +91,16 @@ function ShowPage(WebAdmin, TemplateRequest)
    ]]) - + local AllPlugins = WebAdmin:GetPlugins() for key,value in pairs(AllPlugins) do local PluginWebTitle = value:GetWebTitle() local TabNames = value:GetTabNames() if (GetTableSize(TabNames) > 0) then - Output("
  • "..PluginWebTitle.."
  • "); + Output("
  • "..PluginWebTitle.."
  • \n"); for webname,prettyname in pairs(TabNames) do - Output("
  • " .. prettyname .. "
  • ") + Output("
  • " .. prettyname .. "
  • \n") end end end From ceb1a464497ad8babf079278b1b6eca446eaf141 Mon Sep 17 00:00:00 2001 From: Howaner Date: Sun, 31 Aug 2014 14:52:44 +0200 Subject: [PATCH 318/751] WebAdmin: Added favicon to the login template. --- MCServer/webadmin/login_template.html | 1 + 1 file changed, 1 insertion(+) diff --git a/MCServer/webadmin/login_template.html b/MCServer/webadmin/login_template.html index dd456607c..913a85db0 100644 --- a/MCServer/webadmin/login_template.html +++ b/MCServer/webadmin/login_template.html @@ -2,6 +2,7 @@ MCServer WebAdmin - Login +