summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ClientHandle.cpp11
-rw-r--r--src/Entities/Boat.cpp2
-rw-r--r--src/Entities/Entity.h2
-rw-r--r--src/Entities/ItemFrame.cpp2
-rw-r--r--src/Entities/Minecart.cpp5
-rw-r--r--src/Entities/Pawn.cpp9
-rw-r--r--src/Entities/Player.cpp47
-rw-r--r--src/Entities/Player.h15
-rw-r--r--src/Mobs/Monster.cpp54
-rw-r--r--src/Mobs/Monster.h23
-rw-r--r--src/Mobs/Sheep.cpp2
-rw-r--r--src/Protocol/Protocol125.cpp15
-rw-r--r--src/Protocol/Protocol132.cpp9
-rw-r--r--src/Protocol/Protocol17x.cpp35
-rw-r--r--src/Protocol/Protocol18x.cpp19
-rw-r--r--src/World.cpp8
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp13
18 files changed, 242 insertions, 31 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 43a4161e4..1e2f4ffad 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -124,13 +124,14 @@ cClientHandle::~cClientHandle()
if (m_Player != NULL)
{
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 (!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();
}
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 8ff8866a1..328a70846 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -62,6 +62,8 @@ bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
void cBoat::OnRightClicked(cPlayer & a_Player)
{
+ super::OnRightClicked(a_Player);
+
if (m_Attachee != NULL)
{
if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 6bc070dcc..3fa7e80c1 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -447,7 +447,7 @@ public:
// tolua_end
/// 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().
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL)
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index 7f923ef61..f512324eb 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -22,6 +22,8 @@ cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_
void cItemFrame::OnRightClicked(cPlayer & a_Player)
{
+ super::OnRightClicked(a_Player);
+
if (!m_Item.IsEmpty())
{
// Item not empty, rotate, clipping values to zero to three inclusive
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 5833cb4ae..2df64d5c1 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -1073,6 +1073,8 @@ cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const c
void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
{
+ super::OnRightClicked(a_Player);
+
if (m_Attachee != NULL)
{
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)
{
- // Show the chest UI window to the player
- // TODO
+ // TODO: Show the chest UI window to the player
}
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index fe6c24a7a..fc8ca3d47 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -9,9 +9,9 @@
-cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height):
- super(a_EntityType, 0, 0, 0, a_Width, a_Height),
- m_EntityEffects(tEffectMap())
+cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) :
+ super(a_EntityType, 0, 0, 0, a_Width, a_Height)
+ , m_EntityEffects(tEffectMap())
{
}
@@ -111,3 +111,6 @@ void cPawn::ClearEntityEffects()
RemoveEntityEffect(EffectType);
}
}
+
+
+
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 871311e86..1bdb752c5 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -81,7 +81,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
m_Team(NULL),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
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_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)
{
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)
{
cItems Drops;
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index d64dd6b99..ffd0b7e03 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -254,6 +254,9 @@ public:
The returned value either is empty, or includes the cChatColor::Delimiter. */
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 */
void TossEquippedItem(char a_Amount = 1);
@@ -401,6 +404,16 @@ public:
/** If true the player can fly even when he's not in creative. */
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
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. */
AString m_UUID;
+ AString m_CustomName;
+
/** 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;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 81acf1a93..339367f47 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -75,6 +75,8 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_IdleInterval(0)
, m_DestroyTimer(0)
, m_MobType(a_MobType)
+ , m_CustomName("")
+ , m_CustomNameAlwaysVisible(false)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
, 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
// monster sez: Do I see the player
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)
{
cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name);
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index ca3c04c23..4865cb99e 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -92,6 +92,8 @@ public:
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
virtual bool ReachedDestination(void);
@@ -147,7 +149,24 @@ public:
virtual bool IsSitting (void) const { return false; }
// 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
static AString MobTypeToString(eType a_MobType);
@@ -231,6 +250,8 @@ protected:
float m_DestroyTimer;
eType m_MobType;
+ AString m_CustomName;
+ bool m_CustomNameAlwaysVisible;
AString m_SoundHurt;
AString m_SoundDeath;
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 1a82115d2..c12e8d786 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -54,6 +54,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
+ super::OnRightClicked(a_Player);
+
const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 4378ef466..ba4cfa7ef 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -723,7 +723,7 @@ void cProtocol125::SendPlayerListAddPlayer(const cPlayer & a_Player)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_LIST_ITEM);
- WriteString(a_Player.GetName());
+ WriteString(a_Player.GetPlayerListName());
WriteBool (true);
WriteShort (a_Player.GetClientHandle()->GetPing());
Flush();
@@ -737,7 +737,7 @@ void cProtocol125::SendPlayerListRemovePlayer(const cPlayer & a_Player)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_LIST_ITEM);
- WriteString(a_Player.GetName());
+ WriteString(a_Player.GetPlayerListName());
WriteBool (false);
WriteShort (0);
Flush();
@@ -769,7 +769,7 @@ void cProtocol125::SendPlayerListUpdatePing(const cPlayer & a_Player)
void cProtocol125::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_OldListName)
{
- if (a_OldListName == a_Player.GetName())
+ if (a_OldListName == a_Player.GetPlayerListName())
{
return;
}
@@ -843,7 +843,14 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_SPAWN);
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.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 5fd2655b8..63a15c082 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -260,7 +260,14 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_PLAYER_SPAWN);
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.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 2fbc58541..67a4c47a7 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -795,7 +795,7 @@ void cProtocol172::SendPlayerListAddPlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
- Pkt.WriteString(a_Player.GetName());
+ Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(true);
Pkt.WriteShort(a_Player.GetClientHandle()->GetPing());
}
@@ -809,7 +809,7 @@ void cProtocol172::SendPlayerListRemovePlayer(const cPlayer & a_Player)
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38);
- Pkt.WriteString(a_Player.GetName());
+ Pkt.WriteString(a_Player.GetPlayerListName());
Pkt.WriteBool(false);
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)
{
ASSERT(m_State == 3); // In game mode?
- if (a_OldListName == a_Player.GetName())
+ if (a_OldListName == a_Player.GetPlayerListName())
{
return;
}
@@ -928,9 +928,16 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
// Called to spawn another player for the client
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(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.GetPosY());
Pkt.WriteFPInt(a_Player.GetPosZ());
@@ -2928,6 +2935,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
break;
}
} // 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
Pkt.WriteVarInt(a_Player.GetUniqueID());
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();
Pkt.WriteVarInt(Properties.size());
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index a7ab3abb1..e2ea6701a 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -824,7 +824,17 @@ void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player)
Pkt.WriteVarInt((UInt32)a_Player.GetGameMode());
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)
{
- UNUSED(a_OldListName);
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
@@ -885,15 +894,15 @@ void cProtocol180::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, con
Pkt.WriteVarInt(1);
Pkt.WriteUUID(a_Player.GetUUID());
- // TODO: Replace this with GetPlayerListName() (It's already done in other pull request)
- if (a_Player.GetName().empty())
+ AString CustomName = a_Player.GetPlayerListName();
+ if (CustomName == a_Player.GetName())
{
Pkt.WriteBool(false);
}
else
{
Pkt.WriteBool(true);
- Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Player.GetName().c_str()));
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", CustomName.c_str()));
}
}
diff --git a/src/World.cpp b/src/World.cpp
index 71ce7e680..8664bbec6 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -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)
{
AString PlayerName ((*itr)->GetName());
+ if ((*itr)->HasCustomName())
+ {
+ PlayerName = (*itr)->GetCustomName();
+ }
+
AString::size_type Found = PlayerName.find(LastWord); // Try to find last word in playername
-
if (Found == AString::npos)
{
continue; // No match
}
-
+
UsernamesByWeight.push_back(std::make_pair(Found, PlayerName)); // Match! Store it with the position of the match as a weight
}
Lock.Unlock();
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 68e541eba..1962d42ff 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -504,6 +504,8 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddFloat("", a_Monster->GetDropChanceBoots());
m_Writer.EndList();
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())
{
case cMonster::mtBat:
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index fe309ce4e..10cc39083 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -2652,6 +2652,19 @@ bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT &
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;
}