summaryrefslogtreecommitdiffstats
path: root/src/ClientHandle.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ClientHandle.cpp485
1 files changed, 299 insertions, 186 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index b390bf2d6..3b677460b 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"
@@ -74,14 +75,25 @@ 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")
+ m_Locale("en_GB"),
+ m_ProtocolVersion(0)
{
m_Protocol = new cProtocolRecognizer(this);
@@ -113,13 +125,14 @@ cClientHandle::~cClientHandle()
if (m_Player != NULL)
{
cWorld * World = m_Player->GetWorld();
- if (!m_Username.empty() && (World != NULL))
- {
- // Send the Offline PlayerList packet:
- World->BroadcastPlayerListItem(*m_Player, false, this);
- }
if (World != NULL)
{
+ if (!m_Username.empty())
+ {
+ // Send the Offline PlayerList packet:
+ World->BroadcastPlayerListRemovePlayer(*m_Player, this);
+ }
+
World->RemovePlayer(m_Player, true); // Must be called before cPlayer::Destroy() as otherwise cChunk tries to delete the player, and then we do it again
m_Player->Destroy();
}
@@ -233,13 +246,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],
@@ -300,8 +314,16 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
ASSERT(m_Player == NULL);
m_Username = a_Name;
- m_UUID = a_UUID;
- m_Properties = a_Properties;
+
+ // Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):
+ if (m_UUID.empty())
+ {
+ m_UUID = a_UUID;
+ }
+ if (m_Properties.empty())
+ {
+ m_Properties = a_Properties;
+ }
// Send login success (if the protocol supports it):
m_Protocol->SendLoginSuccess();
@@ -339,8 +361,8 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
m_Protocol->SendWeather(World->GetWeather());
}
- // Send time
- m_Protocol->SendTimeUpdate(World->GetWorldAge(), World->GetTimeOfDay());
+ // Send time:
+ m_Protocol->SendTimeUpdate(World->GetWorldAge(), World->GetTimeOfDay(), World->IsDaylightCycleEnabled());
// Send contents of the inventory window
m_Protocol->SendWholeInventory(*m_Player->GetWindow());
@@ -350,7 +372,12 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
// Send experience
m_Player->SendExperience();
-
+
+ // Send player list items
+ SendPlayerListAddPlayer(*m_Player);
+ World->BroadcastPlayerListAddPlayer(*m_Player);
+ World->SendPlayerList(m_Player);
+
m_Player->Initialize(*World);
m_State = csAuthenticated;
@@ -460,13 +487,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
}
@@ -489,8 +516,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);
}
@@ -525,6 +552,16 @@ void cClientHandle::RemoveFromAllChunks()
+void cClientHandle::HandleNPCTrade(int a_SlotNum)
+{
+ // TODO
+ LOGWARNING("%s: Not implemented yet", __FUNCTION__);
+}
+
+
+
+
+
void cClientHandle::HandlePing(void)
{
// Somebody tries to retrieve information about the server
@@ -547,16 +584,22 @@ void cClientHandle::HandlePing(void)
bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Username)
{
- LOGD("LOGIN %s", a_Username.c_str());
+ // If the protocol version hasn't been set yet, set it now:
+ if (m_ProtocolVersion == 0)
+ {
+ m_ProtocolVersion = a_ProtocolVersion;
+ }
+
m_Username = a_Username;
+ // Let the plugins know about this event, they may refuse the player:
if (cRoot::Get()->GetPluginManager()->CallHookLogin(this, a_ProtocolVersion, a_Username))
{
Destroy();
return false;
}
- // Schedule for authentication; until then, let them wait (but do not block)
+ // Schedule for authentication; until then, let the player wait (but do not block)
m_State = csAuthenticating;
cRoot::Get()->GetAuthenticator().Authenticate(GetUniqueID(), GetUsername(), m_Protocol->GetAuthServerID());
return true;
@@ -634,6 +677,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
if (!m_Player->IsSwimming())
{
+ m_Player->GetStatManager().AddValue(statJumps, 1);
m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2);
}
}
@@ -649,21 +693,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message)
{
- if (a_Channel == "MC|AdvCdm")
- {
- // Command block, set text, Client -> Server
- HandleCommandBlockMessage(a_Message.c_str(), a_Message.size());
- }
- else if (a_Channel == "MC|Brand")
- {
- // 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 (a_Channel == "REGISTER")
{
if (HasPluginChannel(a_Channel))
{
@@ -746,52 +776,61 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList
-void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length)
+void cClientHandle::HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect)
{
- if (a_Length < 14)
+ cWindow * Window = m_Player->GetWindow();
+ if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon))
{
- SendChat("Failure setting command block command; bad request", mtFailure);
- LOGD("Malformed MC|AdvCdm packet.");
return;
}
+ cBeaconWindow * BeaconWindow = (cBeaconWindow *) Window;
- cByteBuffer Buffer(a_Length);
- Buffer.Write(a_Data, a_Length);
+ if (Window->GetSlot(*m_Player, 0)->IsEmpty())
+ {
+ return;
+ }
- int BlockX, BlockY, BlockZ;
+ cEntityEffect::eType PrimaryEffect = cEntityEffect::effNoEffect;
+ if ((a_PrimaryEffect >= 0) && (a_PrimaryEffect <= (int)cEntityEffect::effSaturation))
+ {
+ PrimaryEffect = (cEntityEffect::eType)a_PrimaryEffect;
+ }
+ cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect;
+ if ((a_SecondaryEffect >= 0) && (a_SecondaryEffect <= (int)cEntityEffect::effSaturation))
+ {
+ SecondaryEffect = (cEntityEffect::eType)a_SecondaryEffect;
+ }
- AString Command;
+ Window->SetSlot(*m_Player, 0, cItem());
+ BeaconWindow->GetBeaconEntity()->SetPrimaryEffect(PrimaryEffect);
- char Mode;
+ // 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);
+ }
- Buffer.ReadChar(Mode);
+ m_Player->CloseWindow(true);
+}
- switch (Mode)
- {
- case 0x00:
- {
- Buffer.ReadBEInt(BlockX);
- Buffer.ReadBEInt(BlockY);
- Buffer.ReadBEInt(BlockZ);
- Buffer.ReadVarUTF8String(Command);
- break;
- }
- default:
- {
- SendChat("Failure setting command block command; unhandled mode", mtFailure);
- LOGD("Unhandled MC|AdvCdm packet mode.");
- return;
- }
- }
- cWorld * World = m_Player->GetWorld();
+void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand)
+{
+ cWorld * World = m_Player->GetWorld();
if (World->AreCommandBlocksEnabled())
{
- World->SetCommandBlockCommand(BlockX, BlockY, BlockZ, Command);
-
+ World->SetCommandBlockCommand(a_BlockX, a_BlockY, a_BlockZ, a_NewCommand);
SendChat("Successfully set command block command", mtSuccess);
}
else
@@ -804,22 +843,26 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Leng
-void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length)
+void cClientHandle::HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand)
{
- if (a_Length < 1)
- {
- return;
- }
+ // TODO
+ LOGWARNING("%s: Not implemented yet", __FUNCTION__);
+}
+
+
+
+
+void cClientHandle::HandleAnvilItemName(const AString & a_ItemName)
+{
if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil))
{
return;
}
- AString Name(a_Data, a_Length);
- if (Name.length() <= 30)
+ if (a_ItemName.length() <= 30)
{
- ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player);
+ ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(a_ItemName, m_Player);
}
}
@@ -841,15 +884,36 @@ 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))
- )
+ if ((a_Status == DIG_STATUS_STARTED) || (a_Status == DIG_STATUS_FINISHED))
{
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
- return;
+ 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;
+ 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 (
+ ((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();
@@ -957,10 +1021,11 @@ 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.
+ // Players can't destroy blocks with a sword in the hand.
return;
}
@@ -980,26 +1045,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
@@ -1051,6 +1096,20 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
FinishDigAnimation();
+ if (!m_Player->IsGameModeCreative())
+ {
+ if (a_OldBlock == E_BLOCK_BEDROCK)
+ {
+ Kick("You can't break a bedrock!");
+ return;
+ }
+ if (a_OldBlock == E_BLOCK_BARRIER)
+ {
+ Kick("You can't break a barrier!");
+ return;
+ }
+ }
+
cWorld * World = m_Player->GetWorld();
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@@ -1067,6 +1126,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());
@@ -1108,50 +1168,61 @@ void cClientHandle::FinishDigAnimation()
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)
{
+ // TODO: Rewrite this function
+
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
);
cWorld * World = m_Player->GetWorld();
+ bool AreRealCoords = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) - m_Player->GetPosition()).Length() <= 5;
if (
(a_BlockFace != BLOCK_FACE_NONE) && // The client is interacting with a specific block
- (
- (Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || // The block is too far away
- (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
- (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
- )
+ IsValidBlock(a_HeldItem.m_ItemType) &&
+ !AreRealCoords
)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
- if (a_BlockY < cChunkDef::Height - 1)
- {
- World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
- }
- if (a_BlockY > 0)
+ if ((a_BlockX != -1) && (a_BlockY >= 0) && (a_BlockZ != -1))
{
- World->SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, m_Player); // 2 block high things
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ if (a_BlockY < cChunkDef::Height - 1)
+ {
+ World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
+ }
+ if (a_BlockY > 0)
+ {
+ World->SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, m_Player); // 2 block high things
+ }
}
m_Player->GetInventory().SendEquippedSlot();
return;
}
+ if (!AreRealCoords)
+ {
+ a_BlockFace = BLOCK_FACE_NONE;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
// A plugin doesn't agree with the action, replace the block on the client and quit:
- cChunkInterface ChunkInterface(World->GetChunkMap());
- BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
- BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- if (a_BlockFace != BLOCK_FACE_NONE)
+ if (AreRealCoords)
{
- 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();
+ cChunkInterface ChunkInterface(World->GetChunkMap());
+ BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
+ BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+
+ 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;
}
@@ -1184,22 +1255,25 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
return;
}
- BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
-
- if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
+ if (AreRealCoords)
{
- if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
+
+ if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{
- // A plugin doesn't agree with using the block, abort
+ if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ {
+ // A plugin doesn't agree with using the block, abort
+ return;
+ }
+ cChunkInterface ChunkInterface(World->GetChunkMap());
+ BlockHandler->OnUse(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
return;
}
- cChunkInterface ChunkInterface(World->GetChunkMap());
- BlockHandler->OnUse(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
- PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
- return;
}
short EquippedDamage = Equipped.m_ItemDamage;
@@ -1212,7 +1286,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;
@@ -1363,8 +1437,20 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
cChunkInterface ChunkInterface(World->GetChunkMap());
NewBlock->OnPlacedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
- // Step sound with 0.8f pitch is used as block placement sound
- World->BroadcastSoundEffect(NewBlock->GetStepSound(), (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.8f);
+ AString PlaceSound = cBlockInfo::GetPlaceSound(BlockType);
+ float Volume = 1.0f, Pitch = 0.8f;
+ if (PlaceSound == "dig.metal")
+ {
+ Pitch = 1.2f;
+ PlaceSound = "dig.stone";
+ }
+ else if (PlaceSound == "random.anvil_land")
+ {
+ Volume = 0.65f;
+ }
+
+ World->BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
+
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
@@ -1611,20 +1697,6 @@ void cClientHandle::HandleRespawn(void)
-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(*this, a_Reason);
-
- m_HasSentDC = true;
- Destroy();
-}
-
-
-
-
-
void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
{
if (a_KeepAliveID == m_PingID)
@@ -1972,28 +2044,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));
}
@@ -2227,18 +2288,18 @@ void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cI
-void cClientHandle::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
+void cClientHandle::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale)
{
- m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length);
+ m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length, m_Scale);
}
-void cClientHandle::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
+void cClientHandle::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale)
{
- m_Protocol->SendMapDecorators(a_ID, a_Decorators);
+ m_Protocol->SendMapDecorators(a_ID, a_Decorators, m_Scale);
}
@@ -2254,9 +2315,9 @@ void cClientHandle::SendMapInfo(int a_ID, unsigned int a_Scale)
-void cClientHandle::SendParticleEffect(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)
+void cClientHandle::SendParticleEffect(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_ParticleAmount)
{
- m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
+ m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmount);
}
@@ -2298,9 +2359,45 @@ void cClientHandle::SendPlayerAbilities()
-void cClientHandle::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
+void cClientHandle::SendPlayerListAddPlayer(const cPlayer & a_Player)
+{
+ m_Protocol->SendPlayerListAddPlayer(a_Player);
+}
+
+
+
+
+
+void cClientHandle::SendPlayerListRemovePlayer(const cPlayer & a_Player)
+{
+ m_Protocol->SendPlayerListRemovePlayer(a_Player);
+}
+
+
+
+
+
+void cClientHandle::SendPlayerListUpdateGameMode(const cPlayer & a_Player)
{
- m_Protocol->SendPlayerListItem(a_Player, a_IsOnline);
+ m_Protocol->SendPlayerListUpdateGameMode(a_Player);
+}
+
+
+
+
+
+void cClientHandle::SendPlayerListUpdatePing(const cPlayer & a_Player)
+{
+ m_Protocol->SendPlayerListUpdatePing(a_Player);
+}
+
+
+
+
+
+void cClientHandle::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName)
+{
+ m_Protocol->SendPlayerListUpdateDisplayName(a_Player, a_CustomName);
}
@@ -2520,9 +2617,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);
}
@@ -2661,7 +2758,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)
{
@@ -2669,7 +2766,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());
}
@@ -2685,9 +2782,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));
}
}
@@ -2785,11 +2882,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))
{