From 25e4f15488c1f56c1571f4aefd216830e62ad52b Mon Sep 17 00:00:00 2001 From: sweetgiorni Date: Tue, 3 Jan 2017 10:57:31 -0800 Subject: [PATCH 1/6] Custom Disconnect Message Adds a m_ShutdownMessage option to the settings. When the stop command is issued, players are kicked with said message before the server shuts down. --- src/Root.cpp | 16 ++++++++++++++++ src/Server.cpp | 1 + src/Server.h | 3 +++ 3 files changed, 20 insertions(+) diff --git a/src/Root.cpp b/src/Root.cpp index 3d3930975..90e5cb9db 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -332,6 +332,22 @@ void cRoot::Start(std::unique_ptr a_OverridesRepo) void cRoot::StopServer() { + // Kick all players from the server with custom disconnect message + class cPlayerCallback : public cPlayerListCallback + { + AString m_ShutdownMessage; + virtual bool Item(cPlayer * a_Player) + { + a_Player->GetClientHandlePtr()->Kick(m_ShutdownMessage); + return false; + } + public: + cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) {} + }PlayerCallback((m_Server->GetShutdownMessage())); + + cRoot::Get()->ForEachPlayer(PlayerCallback); + // What's a better way to do this? + std::this_thread::sleep_for(std::chrono::seconds(1)); m_TerminateEventRaised = true; m_StopEvent.Set(); m_InputThreadRunFlag.clear(); diff --git a/src/Server.cpp b/src/Server.cpp index ba469bd3e..95e0b535b 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -190,6 +190,7 @@ void cServer::PlayerDestroying(const cPlayer * a_Player) bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth) { m_Description = a_Settings.GetValueSet("Server", "Description", "Cuberite - in C++!"); + m_ShutdownMessage = a_Settings.GetValueSet("Server", "ShutdownMessage", "Server shutdown"); m_MaxPlayers = a_Settings.GetValueSetI("Server", "MaxPlayers", 100); m_bIsHardcore = a_Settings.GetValueSetB("Server", "HardcoreEnabled", false); m_bAllowMultiLogin = a_Settings.GetValueSetB("Server", "AllowMultiLogin", false); diff --git a/src/Server.h b/src/Server.h index 600e7ca97..74f9581ae 100644 --- a/src/Server.h +++ b/src/Server.h @@ -64,6 +64,8 @@ public: const AString & GetDescription(void) const {return m_Description; } + const AString & GetShutdownMessage(void) const { return m_ShutdownMessage; } + // Player counts: int GetMaxPlayers(void) const { return m_MaxPlayers; } int GetNumPlayers(void) const; @@ -204,6 +206,7 @@ private: cRCONServer m_RCONServer; AString m_Description; + AString m_ShutdownMessage; AString m_FaviconData; int m_MaxPlayers; bool m_bIsHardcore; From 78b6d54bf86c892827fa0a470375ba50318a0bd0 Mon Sep 17 00:00:00 2001 From: sweetgiorni Date: Tue, 3 Jan 2017 12:18:53 -0800 Subject: [PATCH 2/6] Api Documentation Added API documentation for GetShutdownMessage. Style fix in Root.cpp --- Server/Plugins/APIDump/APIDesc.lua | 10 ++++++++++ src/Root.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index d4a814cb9..2bf9f83b0 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -13002,6 +13002,16 @@ end }, Notes = "Returns the server description set in the settings.ini.", }, + GetShutdownMessage = + { + Returns = + { + { + Type = "string", + }, + }, + Notes = "Returns the shutdown message set in the settings.ini.", + }, GetMaxPlayers = { Returns = diff --git a/src/Root.cpp b/src/Root.cpp index 90e5cb9db..a5567dc9b 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -343,7 +343,7 @@ void cRoot::StopServer() } public: cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) {} - }PlayerCallback((m_Server->GetShutdownMessage())); + } PlayerCallback((m_Server->GetShutdownMessage())); cRoot::Get()->ForEachPlayer(PlayerCallback); // What's a better way to do this? From 0718d82e1a5a6fdfe9346f801fa008f2b37cf69d Mon Sep 17 00:00:00 2001 From: sweetgiorni Date: Tue, 3 Jan 2017 12:26:58 -0800 Subject: [PATCH 3/6] Player check Checks if there are any players connected to the server before running PlayerCallback and waiting 1 second. --- src/Root.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Root.cpp b/src/Root.cpp index a5567dc9b..80366e5c1 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -343,11 +343,14 @@ void cRoot::StopServer() } public: cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) {} - } PlayerCallback((m_Server->GetShutdownMessage())); + }; - cRoot::Get()->ForEachPlayer(PlayerCallback); - // What's a better way to do this? - std::this_thread::sleep_for(std::chrono::seconds(1)); + if (m_Server->GetNumPlayers()) + { + cPlayerCallback PlayerCallback((m_Server->GetShutdownMessage())); + cRoot::Get()->ForEachPlayer(PlayerCallback); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } m_TerminateEventRaised = true; m_StopEvent.Set(); m_InputThreadRunFlag.clear(); From 28cc26c54ca09ed9ceb2ed2df53dc323f0be405c Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 3 Jan 2017 12:19:29 -0800 Subject: [PATCH 4/6] Track skin part and main hand preferences (#3498) --- Server/Plugins/APIDump/APIDesc.lua | 143 +++++++++++++++++++++++++++++ src/Defines.h | 36 ++++++++ src/Entities/Player.cpp | 24 ++++- src/Entities/Player.h | 13 +++ src/Protocol/Protocol_1_10.cpp | 8 ++ src/Protocol/Protocol_1_8.cpp | 20 +++- src/Protocol/Protocol_1_9.cpp | 16 +++- 7 files changed, 253 insertions(+), 7 deletions(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 2bf9f83b0..94082cd94 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -11351,6 +11351,16 @@ a_Player:OpenWindow(Window); }, Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status.", }, + GetMainHand = + { + Returns = + { + { + Type = "eMainHand", + }, + }, + Notes = "Returns the player's main hand.", + }, GetName = { Returns = @@ -11411,6 +11421,16 @@ a_Player:OpenWindow(Window); }, Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting.", }, + GetSkinParts = + { + Returns = + { + { + Type = "number", + }, + }, + Notes = "Returns the player's current set of skin part flags. This is a bitwise OR of various {{eSkinPart}} constants. Note that HasSkinPart may be easier to use in most situations.", + }, GetStance = { Returns = @@ -11535,6 +11555,23 @@ a_Player:OpenWindow(Window); }, Notes = "Returns true if the player has the specified permission", }, + HasSkinPart = + { + Params = + { + { + Name = "Part", + Type = "eSkinPart", + }, + }, + Returns = + { + { + Type = "boolean", + }, + }, + Notes = "Returns true if the player has the specified skin part enabled", + }, Heal = { Params = @@ -12063,6 +12100,17 @@ a_Player:OpenWindow(Window); }, Notes = "Sets the 'IsFishing' flag for the player. The floater entity ID is expected for the true variant, it can be omitted when IsFishing is false. FIXME: Undefined behavior when multiple fishing rods are used simultanously", }, + SetMainHand = + { + Params = + { + { + Name = "Hand", + Type = "eMainHand", + }, + }, + Notes = "Sets the main hand of the player.", + }, SetName = { Params = @@ -12096,6 +12144,17 @@ a_Player:OpenWindow(Window); }, Notes = "Sets whether the player is sprinting or not.", }, + SetSkinParts = + { + Params = + { + { + Name = "Parts", + Type = "number", + }, + }, + Notes = "Sets the skin part flags of the player. The value should be a bitwise OR of several {{eSkinPart}} constants.", + }, SetSprintingMaxSpeed = { Params = @@ -16642,6 +16701,54 @@ end { Notes = "Something concerning (i.e. reload) is about to happen", }, + hMain = + { + Notes = "The main hand", + }, + hOff = + { + Notes = "The off hand", + }, + mhLeft = + { + Notes = "The left hand is the main hand", + }, + mhRight = + { + Notes = "The right hand is the main hand", + }, + spCape = + { + Notes = "The cape skin part", + }, + spJacket = + { + Notes = "The jacket skin part", + }, + spLeftSleeve = + { + Notes = "The left sleeve skin part", + }, + spRightSleeve = + { + Notes = "The right sleeve skin part", + }, + spLeftPants = + { + Notes = "The left pants leg skin part", + }, + spRightPants = + { + Notes = "The right pants leg skin part", + }, + spHat = + { + Notes = "The hat/head skin part", + }, + spMask = + { + Notes = "A mask of all valid skin parts combined", + }, }, ConstantGroups = { @@ -16727,6 +16834,32 @@ end gmXXX constants, the eGameMode_ constants are deprecated and will be removed from the API. ]], }, + eHand = + { + Include = + { + "hMain", + "hOff", + }, + TextBefore = [[ + These constants represent the main and off hand. Currently, these constants are not used, but + are provided for future use when dual-wielding is functional. An action or item can be in the + main hand or the off hand. The main hand can be either the left or the right hand - use + {{cPlayer}}:GetMainHand() to determine which (see {{eMainHand}}). + ]], + }, + eMainHand = + { + Include = + { + "^mh.*", + }, + TextBefore = [[ + These constants identify which hand is the main hand. The main hand can either be the left hand + or the right hand. Note that this is only visual, as the client behaves the same regardless of the + main hand setting. See {{cPlayer}}:GetMainHand(). + ]], + }, EMCSBiome = { Include = "^bi.*", @@ -16819,6 +16952,16 @@ end The following constants define the block types that are propelled outwards after an explosion. ]], }, + eSkinPart = + { + Include = + { + "^sp.*", + }, + TextBefore = [[ + These constants represent various skin part flags. + ]], + }, eSpreadSource = { Include = "^ss.*", diff --git a/src/Defines.h b/src/Defines.h index f8af22ef2..a1de94897 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -203,6 +203,42 @@ enum eMobHeadRotation +enum eHand +{ + hMain = 0, + hOff = 1, +} ; + + + + + +enum eMainHand +{ + mhLeft = 0, + mhRight = 1, +} ; + + + + + +enum eSkinPart +{ + spCape = 0x01, + spJacket = 0x02, + spLeftSleeve = 0x04, + spRightSleeve = 0x08, + spLeftPants = 0x10, + spRightPants = 0x20, + spHat = 0x40, + spMask = 0x7F, +}; + + + + + inline const char * ClickActionToString(int a_ClickAction) { switch (a_ClickAction) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index f3ea45cf4..9fba0d015 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -90,7 +90,9 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_bIsTeleporting(false), m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : ""), - m_CustomName("") + m_CustomName(""), + m_SkinParts(0), + m_MainHand(mhRight) { ASSERT(a_PlayerName.length() <= 16); // Otherwise this player could crash many clients... @@ -2632,6 +2634,26 @@ bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks) +void cPlayer::SetSkinParts(int a_Parts) +{ + m_SkinParts = a_Parts & spMask; + m_World->BroadcastEntityMetadata(*this, m_ClientHandle.get()); +} + + + + + +void cPlayer::SetMainHand(eMainHand a_Hand) +{ + m_MainHand = a_Hand; + m_World->BroadcastEntityMetadata(*this, m_ClientHandle.get()); +} + + + + + void cPlayer::AttachTo(cEntity * a_AttachTo) { // Different attach, if this is a spectator diff --git a/src/Entities/Player.h b/src/Entities/Player.h index dab814692..b592913bd 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -499,6 +499,13 @@ public: The blocks in range (a_BlockX - a_Range, a_BlockX + a_Range) are sent (NY-metric). */ void SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Range = 1); + bool HasSkinPart(eSkinPart a_Part) const { return (m_SkinParts & a_Part) != 0; } + int GetSkinParts(void) const { return m_SkinParts; } + void SetSkinParts(int a_Parts); + + eMainHand GetMainHand(void) const { return m_MainHand; } + void SetMainHand(eMainHand a_Hand); + // tolua_end /** Calls the block placement hooks and places the blocks in the world. @@ -682,6 +689,12 @@ protected: AString m_CustomName; + /** Displayed skin part bit mask */ + int m_SkinParts; + + /** The main hand of the player */ + eMainHand m_MainHand; + /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp index c0d9d921f..1cd7153a7 100644 --- a/src/Protocol/Protocol_1_10.cpp +++ b/src/Protocol/Protocol_1_10.cpp @@ -400,6 +400,14 @@ void cProtocol_1_10_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Pkt.WriteBEUInt8(LIVING_HEALTH); a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT); a_Pkt.WriteBEFloat(static_cast(Player.GetHealth())); + + a_Pkt.WriteBEUInt8(PLAYER_DISPLAYED_SKIN_PARTS); + a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); + a_Pkt.WriteBEUInt8(static_cast(Player.GetSkinParts())); + + a_Pkt.WriteBEUInt8(PLAYER_MAIN_HAND); + a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); + a_Pkt.WriteBEUInt8(static_cast(Player.GetMainHand())); break; } case cEntity::etPickup: diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index bbeb3ae8b..2e7902303 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -2311,11 +2311,12 @@ void cProtocol_1_8_0::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance); HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags); HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors); - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinFlags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinParts); m_Client->SetLocale(Locale); m_Client->SetViewDistance(ViewDistance); - // TODO: Handle other values + m_Client->GetPlayer()->SetSkinParts(SkinParts); + // TODO: Handle chat flags and chat colors } @@ -3234,7 +3235,20 @@ void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a switch (a_Entity.GetEntityType()) { - case cEntity::etPlayer: break; // TODO? + case cEntity::etPlayer: + { + auto & Player = reinterpret_cast(a_Entity); + + // Player health (not handled since players aren't monsters) + a_Pkt.WriteBEUInt8(0x66); + a_Pkt.WriteBEFloat(static_cast(Player.GetHealth())); + + // Skin flags + a_Pkt.WriteBEUInt8(0x0A); + a_Pkt.WriteBEUInt8(static_cast(Player.GetSkinParts())); + + break; + } case cEntity::etPickup: { a_Pkt.WriteBEUInt8((5 << 5) | 10); // Slot(5) + index 10 diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 680675ca3..69b8deb55 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -2355,12 +2355,14 @@ void cProtocol_1_9_0::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ViewDistance); HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ChatFlags); HANDLE_READ(a_ByteBuffer, ReadBool, bool, ChatColors); - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinFlags); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, SkinParts); HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, MainHand); m_Client->SetLocale(Locale); m_Client->SetViewDistance(ViewDistance); - // TODO: Handle other values + m_Client->GetPlayer()->SetSkinParts(SkinParts); + m_Client->GetPlayer()->SetMainHand(static_cast(MainHand)); + // TODO: Handle chat flags and chat colors } @@ -3552,9 +3554,17 @@ void cProtocol_1_9_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a a_Pkt.WriteBEUInt8(METADATA_TYPE_STRING); a_Pkt.WriteString(Player.GetName()); - a_Pkt.WriteBEUInt8(6); // Start metadata - Index 6: Health + a_Pkt.WriteBEUInt8(6); // Index 6: Health a_Pkt.WriteBEUInt8(METADATA_TYPE_FLOAT); a_Pkt.WriteBEFloat(static_cast(Player.GetHealth())); + + a_Pkt.WriteBEUInt8(12); + a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); + a_Pkt.WriteBEUInt8(static_cast(Player.GetSkinParts())); + + a_Pkt.WriteBEUInt8(13); + a_Pkt.WriteBEUInt8(METADATA_TYPE_BYTE); + a_Pkt.WriteBEUInt8(static_cast(Player.GetMainHand())); break; } case cEntity::etPickup: From ff1c0605db37bf989fc7e2c920c4852522793432 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Tue, 3 Jan 2017 21:20:01 +0100 Subject: [PATCH 5/6] TCPLink: call networking callbacks with LibEvent unlocked. (#3515) --- src/OSSupport/TCPLinkImpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp index d55dc9da1..47be99a48 100644 --- a/src/OSSupport/TCPLinkImpl.cpp +++ b/src/OSSupport/TCPLinkImpl.cpp @@ -18,7 +18,7 @@ cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks): super(a_LinkCallbacks), - m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE)), + m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)), m_LocalPort(0), m_RemotePort(0), m_ShouldShutdown(false) @@ -31,7 +31,7 @@ cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks): cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr * a_Address, socklen_t a_AddrLen): super(a_LinkCallbacks), - m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE)), + m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)), m_Server(a_Server), m_LocalPort(0), m_RemotePort(0), From 6522385897788df4682a1744b17815c0767c46f8 Mon Sep 17 00:00:00 2001 From: sweetgiorni Date: Tue, 3 Jan 2017 12:39:39 -0800 Subject: [PATCH 6/6] Disconnect sent flag added Truthiness no longer assumed --- src/Root.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Root.cpp b/src/Root.cpp index 80366e5c1..8390cac7b 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -339,16 +339,17 @@ void cRoot::StopServer() virtual bool Item(cPlayer * a_Player) { a_Player->GetClientHandlePtr()->Kick(m_ShutdownMessage); + m_HasSentDisconnect = true; return false; } public: - cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) {} - }; + bool m_HasSentDisconnect; + cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) { m_HasSentDisconnect = false; } + } PlayerCallback(m_Server->GetShutdownMessage()); - if (m_Server->GetNumPlayers()) + cRoot::Get()->ForEachPlayer(PlayerCallback); + if (PlayerCallback.m_HasSentDisconnect) { - cPlayerCallback PlayerCallback((m_Server->GetShutdownMessage())); - cRoot::Get()->ForEachPlayer(PlayerCallback); std::this_thread::sleep_for(std::chrono::seconds(1)); } m_TerminateEventRaised = true;