From 054a89dd9e5d6819adede9d7ba781b69f98ff2f4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 6 Jan 2021 00:35:42 +0000 Subject: Clarify cClientHandle, cPlayer ownership semantics + A cPlayer, once created, has a strong pointer to the cClientHandle. The player ticks the clienthandle. If he finds the handle destroyed, he destroys himself in turn. Nothing else can kill the player. * The client handle has a pointer to the player. Once a player is created, the client handle never outlasts the player, nor does it manage the player's lifetime. The pointer is always safe to use after FinishAuthenticate, which is also the point where cProtocol is put into the Game state that allows player manipulation. + Entities are once again never lost by constructing a chunk when they try to move into one that doesn't exist. * Fixed a forgotten Super invocation in cPlayer::OnRemoveFromWorld. * Fix SaveToDisk usage in destructor by only saving things cPlayer owns, instead of accessing cWorld. --- src/ClientHandle.h | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) (limited to 'src/ClientHandle.h') diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 555c4396a..2662f20d6 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -45,7 +45,7 @@ typedef std::shared_ptr cClientHandlePtr; class cClientHandle // tolua_export - : public cTCPLink::cCallbacks + : public cTCPLink::cCallbacks, public std::enable_shared_from_this { // tolua_export public: // tolua_export @@ -136,7 +136,6 @@ public: // tolua_export bool IsPlaying (void) const { return (m_State == csPlaying); } bool IsDestroyed (void) const { return (m_State == csDestroyed); } - bool IsDestroying(void) const { return (m_State == csDestroying); } // The following functions send the various packets: // (Please keep these alpha-sorted) @@ -197,7 +196,7 @@ public: // tolua_export void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); void SendResourcePack (const AString & a_ResourcePackUrl); void SendResetTitle (void); // tolua_export - void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false); + void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks); void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void SendSetSubTitle (const cCompositeChat & a_SubTitle); // tolua_export @@ -401,9 +400,6 @@ public: // tolua_export bool IsPlayerChunkSent(); private: - /** The dimension that was last sent to a player in a Respawn or Login packet. - Used to avoid Respawning into the same dimension, which confuses the client. */ - eDimension m_LastSentDimension; friend class cServer; // Needs access to SetSelf() @@ -447,17 +443,12 @@ private: /** Protects m_OutgoingData against multithreaded access. */ cCriticalSection m_CSOutgoingData; - /** Buffer for storing outgoing data from any thread; will get sent in Tick() (to prevent deadlocks). - Protected by m_CSOutgoingData. */ - ContiguousByteBuffer m_OutgoingData; - - Vector3d m_ConfirmPosition; - + /** A pointer to a World-owned player object, created in FinishAuthenticate when authentication succeeds. + The player should only be accessed from the tick thread of the World that owns him. + After the player object is handed off to the World, lifetime is managed automatically, guaranteed to outlast this client handle. + The player self-destructs some time after the client handle enters the Destroyed state. */ cPlayer * m_Player; - // Temporary (#3115-will-fix): maintain temporary ownership of created cPlayer objects while they are in limbo - std::unique_ptr m_PlayerPtr; - /** This is an optimization which saves you an iteration of m_SentChunks if you just want to know whether or not the player is standing at a sent chunk. If this is equal to the coordinates of the chunk the player is currrently standing at, then this must be a sent chunk @@ -500,12 +491,8 @@ private: { csConnected, ///< The client has just connected, waiting for their handshake / login csAuthenticating, ///< The client has logged in, waiting for external authentication - csAuthenticated, ///< The client has been authenticated, will start streaming chunks in the next tick csDownloadingWorld, ///< The client is waiting for chunks, we're waiting for the loader to provide and send them csPlaying, ///< Normal gameplay - csKicked, ///< Disconnect packet sent, awaiting connection closure - csQueuedForDestruction, ///< The client will be destroyed in the next tick (flag set when socket closed) - csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread } ; @@ -555,9 +542,6 @@ private: m_CSOutgoingData is used to synchronize access for sending data. */ cTCPLinkPtr m_Link; - /** Shared pointer to self, so that this instance can keep itself alive when needed. */ - cClientHandlePtr m_Self; - /** The fraction between 0 and 1 (or above), of how far through mining the currently mined block is. 0 for just started, 1 and above for broken. Used for anti-cheat. */ float m_BreakProgress; @@ -592,16 +576,13 @@ private: /** Called when the network socket has been closed. */ void SocketClosed(void); - /** Called right after the instance is created to store its SharedPtr inside. */ - void SetSelf(cClientHandlePtr a_Self); - /** Called to update m_State. Only succeeds if a_NewState > m_State, otherwise returns false. */ bool SetState(eState a_NewState); - /** Processes the data in the network input and output buffers. + /** Processes the data in the network input buffer. Called by both Tick() and ServerTick(). */ - void ProcessProtocolInOut(void); + void ProcessProtocolIn(void); // cTCPLink::cCallbacks overrides: virtual void OnLinkCreated(cTCPLinkPtr a_Link) override; -- cgit v1.2.3