1
0

Merge pull request #1372 from mc-server/EntityCustomName

Added SetCustomName() to cMonster and cPlayer
This commit is contained in:
Franz Reiter 2014-09-23 15:54:07 +02:00
commit 33f8091d5f
20 changed files with 267 additions and 31 deletions

View File

@ -1634,6 +1634,11 @@ a_Player:OpenWindow(Window);
]], ]],
Functions = Functions =
{ {
HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the monster has a custom name." },
GetCustomName = { Params = "", Return = "string", Notes = "Gets the custom name of the monster. If no custom name is set, the function returns an empty string." },
SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of the monster. You see the name over the monster. If you want to disable the custom name, simply set an empty string." },
IsCustomNameAlwaysVisible = { Params = "", Return = "bool", Notes = "Is the custom name of this monster always visible? If not, you only see the name when you sight the mob." },
SetCustomNameAlwaysVisible = { Params = "bool", Return = "", Notes = "Sets the custom name visiblity of this monster. If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name." },
FamilyFromType = { Params = "{{cMonster#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{cMonster#MobType|mtXXX}} constants)" }, FamilyFromType = { Params = "{{cMonster#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{cMonster#MobType|mtXXX}} constants)" },
GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" }, GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" },
GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" }, GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" },
@ -1759,6 +1764,7 @@ a_Player:OpenWindow(Window);
ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." }, ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." },
GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." }, GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player's messages (based on their rank). Prefix player messages with this code." }, GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player's messages (based on their rank). Prefix player messages with this code." },
GetPlayerListName = { Return = "string", Notes = "Returns the name that is used in the playerlist." },
GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" }, GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" },
GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." }, GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." },
GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." },
@ -1809,6 +1815,9 @@ a_Player:OpenWindow(Window);
SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." }, SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." },
SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." }, SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." },
SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." }, SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." },
HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the player has a custom name." },
GetCustomName = { Params = "", Return = "string", Notes = "Returns the custom name of this player. If the player hasn't a custom name, it will return an empty string." },
SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of this player. If you want to disable the custom name, simply set an empty string. The custom name will be used in the tab-list, in the player nametag and in the tab-completion." },
SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." }, SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." },
SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." }, SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." },
SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." }, SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." },

View File

@ -38,6 +38,7 @@ function Initialize(Plugin)
-- _X: Disabled so that the normal operation doesn't interfere with anything -- _X: Disabled so that the normal operation doesn't interfere with anything
-- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated); -- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:BindCommand("/nick", "debuggers", HandleNickCmd, "- Gives you a custom name");
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities"); PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities"); PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool"); PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
@ -770,6 +771,21 @@ end
function HandleNickCmd(Split, Player)
if (Split[2] == nil) then
Player:SendMessage("Usage: /nick [CustomName]");
return true;
end
Player:SetCustomName(Split[2]);
Player:SendMessageSuccess("Custom name setted to " .. Player:GetCustomName() .. "!")
return true
end
function HandleListEntitiesCmd(Split, Player) function HandleListEntitiesCmd(Split, Player)
local NumEntities = 0; local NumEntities = 0;

View File

@ -124,13 +124,14 @@ cClientHandle::~cClientHandle()
if (m_Player != NULL) if (m_Player != NULL)
{ {
cWorld * World = m_Player->GetWorld(); cWorld * World = m_Player->GetWorld();
if (!m_Username.empty() && (World != NULL))
{
// Send the Offline PlayerList packet:
World->BroadcastPlayerListRemovePlayer(*m_Player, this);
}
if (World != NULL) 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 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(); m_Player->Destroy();
} }

View File

@ -62,6 +62,8 @@ bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
void cBoat::OnRightClicked(cPlayer & a_Player) void cBoat::OnRightClicked(cPlayer & a_Player)
{ {
super::OnRightClicked(a_Player);
if (m_Attachee != NULL) if (m_Attachee != NULL)
{ {
if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())

View File

@ -447,7 +447,7 @@ public:
// tolua_end // tolua_end
/// Called when the specified player right-clicks this entity /// Called when the specified player right-clicks this entity
virtual void OnRightClicked(cPlayer &) {} virtual void OnRightClicked(cPlayer & a_Player) {}
/// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy(). /// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy().
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL)

View File

@ -22,6 +22,8 @@ cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_
void cItemFrame::OnRightClicked(cPlayer & a_Player) void cItemFrame::OnRightClicked(cPlayer & a_Player)
{ {
super::OnRightClicked(a_Player);
if (!m_Item.IsEmpty()) if (!m_Item.IsEmpty())
{ {
// Item not empty, rotate, clipping values to zero to three inclusive // Item not empty, rotate, clipping values to zero to three inclusive

View File

@ -1073,6 +1073,8 @@ cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const c
void cRideableMinecart::OnRightClicked(cPlayer & a_Player) void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
{ {
super::OnRightClicked(a_Player);
if (m_Attachee != NULL) if (m_Attachee != NULL)
{ {
if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
@ -1125,8 +1127,7 @@ void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item)
void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
{ {
// Show the chest UI window to the player // TODO: Show the chest UI window to the player
// TODO
} }

View File

@ -9,9 +9,9 @@
cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height): cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) :
super(a_EntityType, 0, 0, 0, a_Width, a_Height), super(a_EntityType, 0, 0, 0, a_Width, a_Height)
m_EntityEffects(tEffectMap()) , m_EntityEffects(tEffectMap())
{ {
} }
@ -111,3 +111,6 @@ void cPawn::ClearEntityEffects()
RemoveEntityEffect(EffectType); RemoveEntityEffect(EffectType);
} }
} }

View File

@ -81,7 +81,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
m_Team(NULL), m_Team(NULL),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
m_bIsTeleporting(false), m_bIsTeleporting(false),
m_UUID((a_Client != NULL) ? a_Client->GetUUID() : "") m_UUID((a_Client != NULL) ? a_Client->GetUUID() : ""),
m_CustomName("")
{ {
m_InventoryWindow = new cInventoryWindow(*this); m_InventoryWindow = new cInventoryWindow(*this);
m_CurrentWindow = m_InventoryWindow; m_CurrentWindow = m_InventoryWindow;
@ -809,6 +810,28 @@ void cPlayer::SetCanFly(bool a_CanFly)
void cPlayer::SetCustomName(const AString & a_CustomName)
{
if (m_CustomName == a_CustomName)
{
return;
}
AString OldCustomName = m_CustomName;
m_CustomName = a_CustomName;
if (m_CustomName.length() > 16)
{
m_CustomName = m_CustomName.substr(0, 16);
}
m_World->BroadcastPlayerListUpdateDisplayName(*this, m_CustomName);
m_World->BroadcastSpawnEntity(*this, m_ClientHandle);
}
void cPlayer::SetFlying(bool a_IsFlying) void cPlayer::SetFlying(bool a_IsFlying)
{ {
if (a_IsFlying == m_IsFlying) if (a_IsFlying == m_IsFlying)
@ -1450,6 +1473,28 @@ AString cPlayer::GetColor(void) const
AString cPlayer::GetPlayerListName(void) const
{
const AString & Color = GetColor();
if (HasCustomName())
{
return m_CustomName;
}
else if ((GetName().length() <= 14) && !Color.empty())
{
return Printf("%s%s", Color.c_str(), GetName().c_str());
}
else
{
return GetName();
}
}
void cPlayer::TossEquippedItem(char a_Amount) void cPlayer::TossEquippedItem(char a_Amount)
{ {
cItems Drops; cItems Drops;

View File

@ -254,6 +254,9 @@ public:
The returned value either is empty, or includes the cChatColor::Delimiter. */ The returned value either is empty, or includes the cChatColor::Delimiter. */
AString GetColor(void) const; AString GetColor(void) const;
/** Returns the name that is used in the playerlist. */
AString GetPlayerListName(void) const;
/** tosses the item in the selected hotbar slot */ /** tosses the item in the selected hotbar slot */
void TossEquippedItem(char a_Amount = 1); void TossEquippedItem(char a_Amount = 1);
@ -401,6 +404,16 @@ public:
/** If true the player can fly even when he's not in creative. */ /** If true the player can fly even when he's not in creative. */
void SetCanFly(bool a_CanFly); void SetCanFly(bool a_CanFly);
/** Returns true if the player has a custom name. */
bool HasCustomName(void) const { return !m_CustomName.empty(); }
/** Returns the custom name of this player. If the player hasn't a custom name, it will return an empty string. */
const AString & GetCustomName(void) const { return m_CustomName; }
/** Sets the custom name of this player. If you want to disable the custom name, simply set an empty string.
The custom name will be used in the tab-list, in the player nametag and in the tab-completion. */
void SetCustomName(const AString & a_CustomName);
/** Gets the last position that the player slept in /** Gets the last position that the player slept in
This is initialised to the world spawn point if the player has not slept in a bed as of yet This is initialised to the world spawn point if the player has not slept in a bed as of yet
*/ */
@ -565,6 +578,8 @@ protected:
If no ClientHandle is given, the UUID is initialized to empty. */ If no ClientHandle is given, the UUID is initialized to empty. */
AString m_UUID; AString m_UUID;
AString m_CustomName;
/** Sets the speed and sends it to the client, so that they are forced to move so. */ /** 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; virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override;

View File

@ -75,6 +75,8 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_IdleInterval(0) , m_IdleInterval(0)
, m_DestroyTimer(0) , m_DestroyTimer(0)
, m_MobType(a_MobType) , m_MobType(a_MobType)
, m_CustomName("")
, m_CustomNameAlwaysVisible(false)
, m_SoundHurt(a_SoundHurt) , m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath) , m_SoundDeath(a_SoundDeath)
, m_AttackRate(3) , m_AttackRate(3)
@ -555,6 +557,25 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI)
void cMonster::OnRightClicked(cPlayer & a_Player)
{
super::OnRightClicked(a_Player);
const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_NAME_TAG) && !EquippedItem.m_CustomName.empty())
{
SetCustomName(EquippedItem.m_CustomName);
if (!a_Player.IsGameModeCreative())
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
}
}
// Checks to see if EventSeePlayer should be fired // Checks to see if EventSeePlayer should be fired
// monster sez: Do I see the player // monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(void) void cMonster::CheckEventSeePlayer(void)
@ -683,6 +704,39 @@ void cMonster::InStateEscaping(float a_Dt)
void cMonster::SetCustomName(const AString & a_CustomName)
{
m_CustomName = a_CustomName;
// The maximal length is 64
if (a_CustomName.length() > 64)
{
m_CustomName = a_CustomName.substr(0, 64);
}
if (m_World != NULL)
{
m_World->BroadcastEntityMetadata(*this);
}
}
void cMonster::SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible)
{
m_CustomNameAlwaysVisible = a_CustomNameAlwaysVisible;
if (m_World != NULL)
{
m_World->BroadcastEntityMetadata(*this);
}
}
void cMonster::GetMonsterConfig(const AString & a_Name) void cMonster::GetMonsterConfig(const AString & a_Name)
{ {
cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name); cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name);

View File

@ -92,6 +92,8 @@ public:
virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
virtual bool ReachedDestination(void); virtual bool ReachedDestination(void);
@ -147,7 +149,24 @@ public:
virtual bool IsSitting (void) const { return false; } virtual bool IsSitting (void) const { return false; }
// tolua_begin // tolua_begin
/** Returns true if the monster has a custom name. */
bool HasCustomName(void) const { return !m_CustomName.empty(); }
/** Gets the custom name of the monster. If no custom name is set, the function returns an empty string. */
const AString & GetCustomName(void) const { return m_CustomName; }
/** Sets the custom name of the monster. You see the name over the monster.
If you want to disable the custom name, simply set an empty string. */
void SetCustomName(const AString & a_CustomName);
/** Is the custom name of this monster always visible? If not, you only see the name when you sight the mob. */
bool IsCustomNameAlwaysVisible(void) const { return m_CustomNameAlwaysVisible; }
/** Sets the custom name visiblity of this monster.
If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name. */
void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible);
/// Translates MobType enum to a string, empty string if unknown /// Translates MobType enum to a string, empty string if unknown
static AString MobTypeToString(eType a_MobType); static AString MobTypeToString(eType a_MobType);
@ -231,6 +250,8 @@ protected:
float m_DestroyTimer; float m_DestroyTimer;
eType m_MobType; eType m_MobType;
AString m_CustomName;
bool m_CustomNameAlwaysVisible;
AString m_SoundHurt; AString m_SoundHurt;
AString m_SoundDeath; AString m_SoundDeath;

View File

@ -54,6 +54,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player) void cSheep::OnRightClicked(cPlayer & a_Player)
{ {
super::OnRightClicked(a_Player);
const cItem & EquippedItem = a_Player.GetEquippedItem(); const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby()) if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{ {

View File

@ -723,7 +723,7 @@ void cProtocol125::SendPlayerListAddPlayer(const cPlayer & a_Player)
{ {
cCSLock Lock(m_CSPacket); cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_LIST_ITEM); WriteByte (PACKET_PLAYER_LIST_ITEM);
WriteString(a_Player.GetName()); WriteString(a_Player.GetPlayerListName());
WriteBool (true); WriteBool (true);
WriteShort (a_Player.GetClientHandle()->GetPing()); WriteShort (a_Player.GetClientHandle()->GetPing());
Flush(); Flush();
@ -737,7 +737,7 @@ void cProtocol125::SendPlayerListRemovePlayer(const cPlayer & a_Player)
{ {
cCSLock Lock(m_CSPacket); cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_LIST_ITEM); WriteByte (PACKET_PLAYER_LIST_ITEM);
WriteString(a_Player.GetName()); WriteString(a_Player.GetPlayerListName());
WriteBool (false); WriteBool (false);
WriteShort (0); WriteShort (0);
Flush(); Flush();
@ -769,7 +769,7 @@ void cProtocol125::SendPlayerListUpdatePing(const cPlayer & a_Player)
void cProtocol125::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName) void cProtocol125::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName)
{ {
if (a_OldListName == a_Player.GetName()) if (a_OldListName == a_Player.GetPlayerListName())
{ {
return; return;
} }
@ -843,7 +843,14 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
cCSLock Lock(m_CSPacket); cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_SPAWN); WriteByte (PACKET_PLAYER_SPAWN);
WriteInt (a_Player.GetUniqueID()); WriteInt (a_Player.GetUniqueID());
WriteString(a_Player.GetName()); if (a_Player.HasCustomName())
{
WriteString(a_Player.GetCustomName());
}
else
{
WriteString(a_Player.GetName());
}
WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32));

View File

@ -260,7 +260,14 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
cCSLock Lock(m_CSPacket); cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_SPAWN); WriteByte (PACKET_PLAYER_SPAWN);
WriteInt (a_Player.GetUniqueID()); WriteInt (a_Player.GetUniqueID());
WriteString(a_Player.GetName()); if (a_Player.HasCustomName())
{
WriteString(a_Player.GetCustomName());
}
else
{
WriteString(a_Player.GetName());
}
WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32));

View File

@ -795,7 +795,7 @@ void cProtocol172::SendPlayerListAddPlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
Pkt.WriteString(a_Player.GetName()); Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(true); Pkt.WriteBool(true);
Pkt.WriteShort(a_Player.GetClientHandle()->GetPing()); Pkt.WriteShort(a_Player.GetClientHandle()->GetPing());
} }
@ -809,7 +809,7 @@ void cProtocol172::SendPlayerListRemovePlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); cPacketizer Pkt(*this, 0x38);
Pkt.WriteString(a_Player.GetName()); Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(false); Pkt.WriteBool(false);
Pkt.WriteShort(0); Pkt.WriteShort(0);
} }
@ -841,7 +841,7 @@ void cProtocol172::SendPlayerListUpdatePing(const cPlayer & a_Player)
void cProtocol172::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName) void cProtocol172::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
if (a_OldListName == a_Player.GetName()) if (a_OldListName == a_Player.GetPlayerListName())
{ {
return; return;
} }
@ -928,9 +928,16 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
// Called to spawn another player for the client // Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteVarInt((UInt32) a_Player.GetUniqueID());
Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID()));
Pkt.WriteString(a_Player.GetName()); if (a_Player.HasCustomName())
{
Pkt.WriteString(a_Player.GetCustomName());
}
else
{
Pkt.WriteString(a_Player.GetName());
}
Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosX());
Pkt.WriteFPInt(a_Player.GetPosY()); Pkt.WriteFPInt(a_Player.GetPosY());
Pkt.WriteFPInt(a_Player.GetPosZ()); Pkt.WriteFPInt(a_Player.GetPosZ());
@ -2928,6 +2935,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
break; break;
} }
} // switch (a_Mob.GetType()) } // switch (a_Mob.GetType())
// Custom name:
if (a_Mob.HasCustomName())
{
WriteByte(0x8a);
WriteString(a_Mob.GetCustomName());
WriteByte(0x0b);
WriteByte(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0);
}
} }
@ -2972,7 +2988,14 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteVarInt(a_Player.GetUniqueID());
Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID())); Pkt.WriteString(cMojangAPI::MakeUUIDDashed(a_Player.GetClientHandle()->GetUUID()));
Pkt.WriteString(a_Player.GetName()); if (a_Player.HasCustomName())
{
Pkt.WriteString(a_Player.GetCustomName());
}
else
{
Pkt.WriteString(a_Player.GetName());
}
const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties();
Pkt.WriteVarInt(Properties.size()); Pkt.WriteVarInt(Properties.size());

View File

@ -824,7 +824,17 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player)
Pkt.WriteVarInt((UInt32)a_Player.GetGameMode()); Pkt.WriteVarInt((UInt32)a_Player.GetGameMode());
Pkt.WriteVarInt((UInt32)a_Player.GetClientHandle()->GetPing()); Pkt.WriteVarInt((UInt32)a_Player.GetClientHandle()->GetPing());
Pkt.WriteBool(false);
AString CustomName = a_Player.GetPlayerListName();
if (CustomName != a_Player.GetName())
{
Pkt.WriteBool(true);
Pkt.WriteString(Printf("{\"text\":\"%s\"}", CustomName.c_str()));
}
else
{
Pkt.WriteBool(false);
}
} }
@ -877,7 +887,6 @@ void cProtocol180::SendPlayerListUpdatePing(const cPlayer & a_Player)
void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName) void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName)
{ {
UNUSED(a_OldListName);
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
@ -885,15 +894,15 @@ void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, con
Pkt.WriteVarInt(1); Pkt.WriteVarInt(1);
Pkt.WriteUUID(a_Player.GetUUID()); Pkt.WriteUUID(a_Player.GetUUID());
// TODO: Replace this with GetPlayerListName() (It's already done in other pull request) AString CustomName = a_Player.GetPlayerListName();
if (a_Player.GetName().empty()) if (CustomName == a_Player.GetName())
{ {
Pkt.WriteBool(false); Pkt.WriteBool(false);
} }
else else
{ {
Pkt.WriteBool(true); Pkt.WriteBool(true);
Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Player.GetName().c_str())); Pkt.WriteString(Printf("{\"text\":\"%s\"}", CustomName.c_str()));
} }
} }

View File

@ -3288,13 +3288,17 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr) for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr)
{ {
AString PlayerName ((*itr)->GetName()); AString PlayerName ((*itr)->GetName());
if ((*itr)->HasCustomName())
{
PlayerName = (*itr)->GetCustomName();
}
AString::size_type Found = PlayerName.find(LastWord); // Try to find last word in playername AString::size_type Found = PlayerName.find(LastWord); // Try to find last word in playername
if (Found == AString::npos) if (Found == AString::npos)
{ {
continue; // No match continue; // No match
} }
UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight
} }
Lock.Unlock(); Lock.Unlock();

View File

@ -504,6 +504,8 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddFloat("", a_Monster->GetDropChanceBoots()); m_Writer.AddFloat("", a_Monster->GetDropChanceBoots());
m_Writer.EndList(); m_Writer.EndList();
m_Writer.AddByte("CanPickUpLoot", (char)a_Monster->CanPickUpLoot()); m_Writer.AddByte("CanPickUpLoot", (char)a_Monster->CanPickUpLoot());
m_Writer.AddString("CustomName", a_Monster->GetCustomName());
m_Writer.AddByte("CustomNameVisible", (char)a_Monster->IsCustomNameAlwaysVisible());
switch (a_Monster->GetMobType()) switch (a_Monster->GetMobType())
{ {
case cMonster::mtBat: case cMonster::mtBat:

View File

@ -2652,6 +2652,19 @@ bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT &
a_Monster.SetCanPickUpLoot(CanPickUpLoot); a_Monster.SetCanPickUpLoot(CanPickUpLoot);
} }
int CustomNameTag = a_NBT.FindChildByName(a_TagIdx, "CustomName");
if ((CustomNameTag > 0) && (a_NBT.GetType(CustomNameTag) == TAG_String))
{
a_Monster.SetCustomName(a_NBT.GetString(CustomNameTag));
}
int CustomNameVisibleTag = a_NBT.FindChildByName(a_TagIdx, "CustomNameVisible");
if ((CustomNameVisibleTag > 0) && (a_NBT.GetType(CustomNameVisibleTag) == TAG_Byte))
{
bool CustomNameVisible = (a_NBT.GetByte(CustomNameVisibleTag) == 1);
a_Monster.SetCustomNameAlwaysVisible(CustomNameVisible);
}
return true; return true;
} }