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 =
{
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)" },
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)" },
@ -1759,6 +1764,7 @@ a_Player:OpenWindow(Window);
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)." },
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" },
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." },
@ -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." },
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." },
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." },
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)." },

View File

@ -38,6 +38,7 @@ function Initialize(Plugin)
-- _X: Disabled so that the normal operation doesn't interfere with anything
-- 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("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
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)
local NumEntities = 0;

View File

@ -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();
}

View File

@ -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())

View File

@ -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)

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)
{
super::OnRightClicked(a_Player);
if (!m_Item.IsEmpty())
{
// 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)
{
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
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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())
{

View File

@ -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));

View File

@ -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));

View File

@ -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());

View File

@ -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()));
}
}

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)
{
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();

View File

@ -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:

View File

@ -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;
}