From b9066ab8f97a0f0dc7ec3104760826a0c303eb0f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 8 Sep 2013 18:36:06 +0200 Subject: Fixed client spawning. The method used for 1.2.5 clients no longer works. Fixes #139. --- source/ClientHandle.cpp | 159 ++++++++++++++++-------------------------------- source/ClientHandle.h | 9 +-- 2 files changed, 54 insertions(+), 114 deletions(-) diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 3d819ee18..966b46719 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -98,6 +98,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) , m_HasStartedDigging(false) , m_CurrentExplosionTick(0) , m_RunningSumExplosions(0) + , m_HasSentPlayerChunk(false) { m_Protocol = new cProtocolRecognizer(this); @@ -489,8 +490,14 @@ void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_Hel void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + // The client hasn't been spawned yet and sends nonsense, we know better + return; + } + /* - // TODO: Invalid stance check + // TODO: Invalid stance check if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65)) { LOGD("Invalid stance"); @@ -499,7 +506,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, } */ - // LOGD("recv player pos: {%0.2f %0.2f %0.2f}, ground: %d", a_PosX, a_PosY, a_PosZ, a_IsOnGround ? 1 : 0); + // If the player has moved too far, "repair" them: Vector3d Pos(a_PosX, a_PosY, a_PosZ); if ((m_Player->GetPosition() - Pos).SqrLength() > 100 * 100) { @@ -513,7 +520,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, { // we only add this exhaustion if the player is not swimming - otherwise we end up with both jump + swim exhaustion - if(! m_Player->IsSwimming() ) + if (!m_Player->IsSwimming()) { m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2); } @@ -997,11 +1004,15 @@ void cClientHandle::HandleChat(const AString & a_Message) void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + return; + } + m_Player->SetRotation (a_Rotation); m_Player->SetHeadYaw (a_Rotation); m_Player->SetPitch (a_Pitch); m_Player->SetTouchGround(a_IsOnGround); - m_Player->WrapRotation(); } @@ -1010,6 +1021,12 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround) { + if ((m_Player == NULL) || (m_State != csPlaying)) + { + // The client hasn't been spawned yet and sends nonsense, we know better + return; + } + /* // TODO: Invalid stance check if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65)) @@ -1019,46 +1036,13 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_ return; } */ - switch (m_State) - { - case csPlaying: - { - m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); - m_Player->SetStance (a_Stance); - m_Player->SetTouchGround(a_IsOnGround); - m_Player->SetHeadYaw (a_Rotation); - m_Player->SetRotation (a_Rotation); - m_Player->SetPitch (a_Pitch); - m_Player->WrapRotation(); - break; - } - - case csDownloadingWorld: - { - Vector3d ReceivedPosition = Vector3d(a_PosX, a_PosY, a_PosZ); - // LOGD("Received MoveLook confirmation: {%0.2f %0.2f %0.2f}", a_PosX, a_PosY, a_PosZ); - - // Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up - double Dist = (ReceivedPosition - m_ConfirmPosition).SqrLength(); - if (Dist < 1.0) - { - if (ReceivedPosition.Equals(m_ConfirmPosition)) - { - LOGINFO("Exact position confirmed by client!"); - } - m_State = csPlaying; - } - else - { - LOGWARNING("Player \"%s\" sent a weird position confirmation %.2f blocks away, retrying", m_Username.c_str(), sqrt(Dist)); - LOGD(" Expected pos: {%0.2f, %0.2f, %0.2f}", m_ConfirmPosition.x, m_ConfirmPosition.y, m_ConfirmPosition.z); - LOGD(" Received pos: {%0.2f, %0.2f, %0.2f}", a_PosX, a_PosY, a_PosZ); - m_ConfirmPosition = m_Player->GetPosition(); - SendPlayerMoveLook(); - } - break; - } - } + + m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); + m_Player->SetStance (a_Stance); + m_Player->SetTouchGround(a_IsOnGround); + m_Player->SetHeadYaw (a_Rotation); + m_Player->SetRotation (a_Rotation); + m_Player->SetPitch (a_Pitch); } @@ -1208,7 +1192,7 @@ void cClientHandle::HandleUseEntity(int a_TargetEntityID, bool a_IsLeftClick) void cClientHandle::HandleRespawn(void) { - if( m_Player == NULL ) + if (m_Player == NULL) { Destroy(); return; @@ -1422,6 +1406,7 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_State = csAuthenticated; m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; + m_HasSentPlayerChunk = false; } @@ -1495,17 +1480,23 @@ void cClientHandle::Tick(float a_Dt) Destroy(); } - if ((m_State == csDownloadingWorld) && m_ShouldCheckDownloaded) - { - CheckIfWorldDownloaded(); - m_ShouldCheckDownloaded = false; - } - if (m_Player == NULL) { return; } + // If the chunk the player's in was just sent, spawn the player: + if (m_HasSentPlayerChunk && (m_State != csPlaying)) + { + if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player)) + { + // Broadcast that this player has joined the game! Yay~ + m_Player->GetWorld()->BroadcastChat(m_Username + " joined the game!", this); + } + m_Protocol->SendPlayerMoveLook(); + m_State = csPlaying; + } + // Send a ping packet: cTimer t1; if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) @@ -1601,14 +1592,6 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ { ASSERT(m_Player != NULL); - if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) - { - if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ())) - { - m_Protocol->SendPlayerMoveLook(); - } - } - // Check chunks being sent, erase them from m_ChunksToSend: bool Found = false; { @@ -1618,11 +1601,6 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ)) { m_ChunksToSend.erase(itr); - - // Make the tick thread check if all the needed chunks have been downloaded - // -- needed to offload this from here due to a deadlock possibility - m_ShouldCheckDownloaded = true; - Found = true; break; } @@ -1637,6 +1615,15 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ } m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); + + // If it is the chunk the player's in, make them spawn (in the tick thread): + if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) + { + if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ())) + { + m_HasSentPlayerChunk = true; + } + } } @@ -2078,50 +2065,6 @@ void cClientHandle::SendWindowProperty(const cWindow & a_Window, int a_Property, -void cClientHandle::CheckIfWorldDownloaded(void) -{ - if (m_State != csDownloadingWorld) - { - return; - } - - bool ShouldSendConfirm = false; - { - cCSLock Lock(m_CSChunkLists); - ShouldSendConfirm = m_ChunksToSend.empty(); - } - - if (ShouldSendConfirm) - { - SendConfirmPosition(); - } -} - - - - - -void cClientHandle::SendConfirmPosition(void) -{ - LOG("Spawning player \"%s\" at {%.2f, %.2f, %.2f}", - m_Username.c_str(), m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ() - ); - - m_State = csConfirmingPos; - - if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player)) - { - // Broadcast that this player has joined the game! Yay~ - m_Player->GetWorld()->BroadcastChat(m_Username + " joined the game!", this); - } - - SendPlayerMoveLook(); -} - - - - - const AString & cClientHandle::GetUsername(void) const { return m_Username; diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 9a2092361..67ddcb0ba 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -299,17 +299,14 @@ private: static int s_ClientCount; int m_UniqueID; + /// Set to true when the chunk where the player is is sent to the client. Used for spawning the player + bool m_HasSentPlayerChunk; + /// Returns true if the rate block interactions is within a reasonable limit (bot protection) bool CheckBlockInteractionsRate(void); - /// Checks whether all loaded chunks have been sent to the client; if so, sends the position to confirm - void CheckIfWorldDownloaded(void); - - /// Sends the PlayerMoveLook packet that the client needs to reply to for the game to start - void SendConfirmPosition(void); - /// Adds a single chunk to be streamed to the client; used by StreamChunks() void StreamChunk(int a_ChunkX, int a_ChunkZ); -- cgit v1.2.3