diff options
Diffstat (limited to 'src/ClientHandle.cpp')
-rw-r--r-- | src/ClientHandle.cpp | 434 |
1 files changed, 277 insertions, 157 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 46c10ae82..9b03bead9 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -24,13 +24,15 @@ #include "Root.h" -#include "Authenticator.h" +#include "Protocol/Authenticator.h" #include "MersenneTwister.h" #include "Protocol/ProtocolRecognizer.h" #include "CompositeChat.h" #include "Items/ItemSword.h" +#include "md5/md5.h" + /** Maximum number of explosions to send this tick, server will start dropping if exceeded */ @@ -175,6 +177,84 @@ void cClientHandle::Destroy(void) +void cClientHandle::GenerateOfflineUUID(void) +{ + m_UUID = GenerateOfflineUUID(m_Username); +} + + + + + +AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2) +{ + if (ShouldAppendChatPrefixes) + return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str()); + else + return Printf("%s", m_Color1.c_str()); +} + + + + + +AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString &a_AdditionalData) +{ + switch (a_ChatPrefix) + { + case mtCustom: return ""; + case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White); + case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White); + case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White); + case mtWarning: return FormatChatPrefix(ShouldAppendChatPrefixes, "WARN", cChatColor::Rose, cChatColor::White); + case mtFatal: return FormatChatPrefix(ShouldAppendChatPrefixes, "FATAL", cChatColor::Red, cChatColor::White); + case mtDeath: return FormatChatPrefix(ShouldAppendChatPrefixes, "DEATH", cChatColor::Gray, cChatColor::White); + case mtJoin: return FormatChatPrefix(ShouldAppendChatPrefixes, "JOIN", cChatColor::Yellow, cChatColor::White); + case mtLeave: return FormatChatPrefix(ShouldAppendChatPrefixes, "LEAVE", cChatColor::Yellow, cChatColor::White); + case mtPrivateMessage: + { + if (ShouldAppendChatPrefixes) + { + return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); + } + else + { + return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); + } + } + } + ASSERT(!"Unhandled chat prefix type!"); + return ""; +} + + + + + +AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) +{ + // 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 + + // Generate an md5 checksum, and use it as base for the ID: + MD5 Checksum(a_Username); + AString UUID = Checksum.hexdigest(); + UUID[12] = '3'; // Version 3 UUID + UUID[16] = '8'; // Variant 1 UUID + + // Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions: + UUID.insert(8, "-"); + UUID.insert(13, "-"); + UUID.insert(18, "-"); + UUID.insert(23, "-"); + + return UUID; +} + + + + + void cClientHandle::Kick(const AString & a_Reason) { if (m_State >= csAuthenticating) // Don't log pings @@ -188,7 +268,7 @@ void cClientHandle::Kick(const AString & a_Reason) -void cClientHandle::Authenticate(void) +void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID) { if (m_State != csAuthenticating) { @@ -197,6 +277,12 @@ void cClientHandle::Authenticate(void) ASSERT( m_Player == NULL ); + m_Username = a_Name; + m_UUID = a_UUID; + + // Send login success (if the protocol supports it): + m_Protocol->SendLoginSuccess(); + // Spawn player (only serversided, so data is loaded) m_Player = new cPlayer(this, GetUsername()); @@ -251,6 +337,11 @@ void cClientHandle::Authenticate(void) // Send scoreboard data World->GetScoreBoard().SendTo(*this); + // Delay the first ping until the client "settles down" + // This should fix #889, "BadCast exception, cannot convert bit to fm" error in client + cTimer t1; + m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds + cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player); } @@ -412,14 +503,16 @@ void cClientHandle::HandlePing(void) { // Somebody tries to retrieve information about the server AString Reply; + const cServer & Server = *cRoot::Get()->GetServer(); + Printf(Reply, "%s%s%i%s%i", - cRoot::Get()->GetServer()->GetDescription().c_str(), + Server.GetDescription().c_str(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetNumPlayers(), + Server.GetNumPlayers(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetMaxPlayers() + Server.GetMaxPlayers() ); - Kick(Reply.c_str()); + Kick(Reply); } @@ -540,6 +633,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); } + else if (a_Channel == "MC|ItemName") + { + HandleAnvilItemName(a_Message.c_str(), a_Message.size()); + } else if (a_Channel == "REGISTER") { if (HasPluginChannel(a_Channel)) @@ -623,7 +720,7 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList -void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length) +void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length) { if (a_Length < 14) { @@ -681,6 +778,29 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int +void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length) +{ + if (a_Length < 1) + { + return; + } + + if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil)) + { + return; + } + + AString Name(a_Data, a_Length); + if (Name.length() <= 30) + { + ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player); + } +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", @@ -695,6 +815,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB return; } + 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; + } + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)) { @@ -758,6 +889,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB case DIG_STATUS_CANCELLED: { // Block breaking cancelled by player + FinishDigAnimation(); return; } @@ -796,7 +928,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc // It is a duplicate packet, drop it right away return; } - + if ( m_Player->IsGameModeCreative() && ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType) @@ -805,14 +937,17 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc // Players can't destroy blocks with a Sword in the hand. return; } - - if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) + + 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) + ) { - // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows: m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); return; } - + // Set the last digging coords to the block being dug, so that they can be checked in DIG_FINISHED to avoid dig/aim bug in the client: m_HasStartedDigging = true; m_LastDigBlockX = a_BlockX; @@ -884,24 +1019,24 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo return; } - m_HasStartedDigging = false; - if (m_BlockDigAnimStage != -1) + FinishDigAnimation(); + + cWorld * World = m_Player->GetWorld(); + cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); + + if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) { - // End dig animation - m_BlockDigAnimStage = -1; - // It seems that 10 ends block animation - m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 10, this); + // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows: + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + return; } - cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); - if (a_OldBlock == E_BLOCK_AIR) { LOGD("Dug air - what the function?"); return; } - - cWorld * World = m_Player->GetWorld(); + 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()); @@ -916,6 +1051,36 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo +void cClientHandle::FinishDigAnimation() +{ + if ( + !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet + (m_LastDigBlockX == -1) || + (m_LastDigBlockY == -1) || + (m_LastDigBlockZ == -1) + ) + { + return; + } + + m_HasStartedDigging = false; + if (m_BlockDigAnimStage != -1) + { + // End dig animation + m_BlockDigAnimStage = -1; + // It seems that 10 ends block animation + m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ, 10, this); + } + + m_BlockDigAnimX = -1; + m_BlockDigAnimY = -1; + m_BlockDigAnimZ = -1; +} + + + + + void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem) { LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s", @@ -923,7 +1088,23 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e ); cWorld * World = m_Player->GetWorld(); - + + 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) + ) + { + if (a_BlockFace != BLOCK_FACE_NONE) + { + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things + m_Player->GetInventory().SendEquippedSlot(); + } + return; + } + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) { @@ -937,10 +1118,13 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things + World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things + m_Player->GetInventory().SendEquippedSlot(); } return; } + + m_NumBlockChangeInteractionsThisTick++; if (!CheckBlockInteractionsRate()) { @@ -960,7 +1144,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e ); // Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block - if (a_BlockFace > -1) + if (a_BlockFace != BLOCK_FACE_NONE) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); @@ -988,11 +1172,11 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType); - if (ItemHandler->IsPlaceable() && (a_BlockFace > -1)) + if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE)) { HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } - else if (ItemHandler->IsFood()) + else if (ItemHandler->IsFood() && !m_Player->IsGameModeCreative()) { if (m_Player->IsSatiated()) { @@ -1026,6 +1210,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler) { + BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); if (a_BlockFace < 0) { // Clicked in air @@ -1036,7 +1221,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e BLOCKTYPE ClickedBlock; NIBBLETYPE ClickedBlockMeta; - BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage); if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) @@ -1053,8 +1237,8 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab? ((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type? ( - (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab - (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab + (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab + (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab ) ) { @@ -1062,7 +1246,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e // If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y) // Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason // Don't touch coordinates if anything else because a dblslab opportunity is present - if((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) + if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) { ++a_BlockY; } @@ -1124,6 +1308,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e { // Handler refused the placement, send that information back to the client: World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player); + m_Player->GetInventory().SendEquippedSlot(); return; } @@ -1133,12 +1318,13 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e { // A plugin doesn't agree with placing the block, revert the block on the client: World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + m_Player->GetInventory().SendEquippedSlot(); return; } // The actual block placement: World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - if (m_Player->GetGameMode() != gmCreative) + if (!m_Player->IsGameModeCreative()) { m_Player->GetInventory().RemoveOneEquippedItem(); } @@ -1173,8 +1359,8 @@ void cClientHandle::HandleChat(const AString & a_Message) Color = AString("@") + Color[2]; } else - { - Color.empty(); + { + Color.clear(); } Msg.AddTextPart(AString("<") + m_Player->GetName() + "> ", Color); Msg.ParseText(a_Message); @@ -1205,28 +1391,8 @@ 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)) - { - LOGD("Invalid stance"); - SendPlayerMoveLook(); - return; - } - */ - - 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->SetYaw (a_Rotation); - m_Player->SetPitch (a_Pitch); + HandlePlayerLook(a_Rotation, a_Pitch, a_IsOnGround); + HandlePlayerPos(a_PosX, a_PosY, a_PosZ, a_Stance, a_IsOnGround); } @@ -1415,7 +1581,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason) { LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason); m_HasSentDC = true; Destroy(); @@ -1530,7 +1696,7 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text) -void cClientHandle::SendData(const char * a_Data, int a_Size) +void cClientHandle::SendData(const char * a_Data, size_t a_Size) { if (m_HasSentDC) { @@ -1545,7 +1711,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size) if (m_OutgoingDataOverflow.empty()) { // No queued overflow data; if this packet fits into the ringbuffer, put it in, otherwise put it in the overflow buffer: - int CanFit = m_OutgoingData.GetFreeSpace(); + size_t CanFit = m_OutgoingData.GetFreeSpace(); if (CanFit > a_Size) { CanFit = a_Size; @@ -1563,7 +1729,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size) { // There is a queued overflow. Append to it, then send as much from its front as possible m_OutgoingDataOverflow.append(a_Data, a_Size); - int CanFit = m_OutgoingData.GetFreeSpace(); + size_t CanFit = m_OutgoingData.GetFreeSpace(); if (CanFit > 128) { // No point in moving the data over if it's not large enough - too much effort for too little an effect @@ -1606,10 +1772,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock - // Instead, the chunks will be streamed when the client is moved to the new world's Tick list, - // by setting state to csAuthenticated - m_State = csAuthenticated; + // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set + // Meanwhile here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; m_HasSentPlayerChunk = false; @@ -1677,13 +1841,16 @@ void cClientHandle::Tick(float a_Dt) } // Send a ping packet: - cTimer t1; - if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) + if (m_State == csPlaying) { - m_PingID++; - m_PingStartTime = t1.GetNowTime(); - m_Protocol->SendKeepAlive(m_PingID); - m_LastPingTime = m_PingStartTime; + cTimer t1; + if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) + { + m_PingID++; + m_PingStartTime = t1.GetNowTime(); + m_Protocol->SendKeepAlive(m_PingID); + m_LastPingTime = m_PingStartTime; + } } // Handle block break animation: @@ -1803,7 +1970,7 @@ 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 = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); @@ -1822,89 +1989,9 @@ void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefi ShouldAppendChatPrefixes = false; } - AString Message; + AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData); - switch (a_ChatPrefix) - { - case mtCustom: break; - case mtFailure: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtInformation: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtSuccess: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Green.c_str()); - break; - } - case mtWarning: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtFatal: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Red.c_str()); - break; - } - case mtDeath: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Gray.c_str()); - break; - } - case mtPrivateMessage: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); - else - Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); - break; - } - case mtJoin: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtLeave: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - default: ASSERT(!"Unhandled chat prefix type!"); return; - } - - Message.append(a_Message); - - m_Protocol->SendChat(Message); + m_Protocol->SendChat(Message.append(a_Message)); } @@ -2101,7 +2188,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo } // Update the statistics: - m_NumExplosionsThisTick += 1; + m_NumExplosionsThisTick++; m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); } @@ -2394,6 +2481,15 @@ void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTy +void cClientHandle::SendStatistics(const cStatManager & a_Manager) +{ + m_Protocol->SendStatistics(a_Manager); +} + + + + + void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results) { m_Protocol->SendTabCompletionResults(a_Results); @@ -2633,12 +2729,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType) -void cClientHandle::DataReceived(const char * a_Data, int a_Size) +bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size) { // Data is received from the client, store it in the buffer to be processed by the Tick thread: m_TimeSinceLastPacket = 0; cCSLock Lock(m_CSIncomingData); m_IncomingData.append(a_Data, a_Size); + return false; } @@ -2673,9 +2770,9 @@ void cClientHandle::SocketClosed(void) LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str()); - if (m_Username != "") // Ignore client pings + if (!m_Username.empty()) // Ignore client pings { - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected"); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected"); } Destroy(); @@ -2685,4 +2782,27 @@ void cClientHandle::SocketClosed(void) +void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment) +{ + cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow(); + cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player); + int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment); + + if (Item.EnchantByXPLevels(BaseEnchantmentLevel)) + { + if (m_Player->IsGameModeCreative() || m_Player->DeltaExperience(-m_Player->XpForLevel(BaseEnchantmentLevel)) >= 0) + { + Window->m_SlotArea->SetSlot(0, *m_Player, Item); + Window->SendSlot(*m_Player, Window->m_SlotArea, 0); + Window->BroadcastWholeWindow(); + + Window->SetProperty(0, 0, *m_Player); + Window->SetProperty(1, 0, *m_Player); + Window->SetProperty(2, 0, *m_Player); + } + } +} + + + |