[Feature] Implement /changename & related script bindings. Clean up #set name (#4770)

* initial work, need to clean up gm commands still

* cleaned up command, works without kicking char select now

* remove thj-specific methods

* add script hooks

* actually clear flag

* rework questmgr::rename

* remove unnecessary logging

* revert

* added missing binding to perl api and updated some text

* don't return a value

* Fix some bad argument types.

* adjust case

* alpha order

* refactor some old string stuff

* don't quote integers, bob

---------

Co-authored-by: Zimp <zimp@zenryo.xyz>
Co-authored-by: Chris Miles <akkadius1@gmail.com>
This commit is contained in:
catapultam-habeo
2025-03-19 19:00:45 -07:00
committed by GitHub
parent be6a5d5f50
commit 213fe6a9e9
14 changed files with 223 additions and 39 deletions
+86 -16
View File
@@ -2549,40 +2549,59 @@ void Client::ChangeLastName(std::string last_name) {
safe_delete(outapp);
}
bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
// Deprecated, this packet does not actually work in ROF2
bool Client::ChangeFirstName(const std::string in_firstname, const std::string gmname)
{
// check duplicate name
bool used_name = database.IsNameUsed((const char*) in_firstname);
if (used_name) {
if (!ChangeFirstName(in_firstname)) {
return false;
}
// update character_
if(!database.UpdateName(GetName(), in_firstname))
return false;
// update pp
memset(m_pp.name, 0, sizeof(m_pp.name));
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname);
strcpy(name, m_pp.name);
Save();
// send name update packet
auto outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct));
GMName_Struct* gmn=(GMName_Struct*)outapp->pBuffer;
strn0cpy(gmn->gmname,gmname,64);
strn0cpy(gmn->gmname,gmname.c_str(),64);
strn0cpy(gmn->oldname,GetName(),64);
strn0cpy(gmn->newname,in_firstname,64);
strn0cpy(gmn->newname,in_firstname.c_str(),64);
gmn->unknown[0] = 1;
gmn->unknown[1] = 1;
gmn->unknown[2] = 1;
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
// success
return true;
}
bool Client::ChangeFirstName(const std::string in_firstname)
{
// check duplicate name
bool used_name = database.IsNameUsed(in_firstname) || database.IsPetNameUsed(in_firstname);
if (used_name || !database.CheckNameFilter(in_firstname, false)) {
return false;
}
// update character_
if(!database.UpdateNameByID(CharacterID(), in_firstname))
return false;
// Send Name Update to Clients
SendRename(this, GetName(), in_firstname.c_str());
SetName(in_firstname.c_str());
// update pp
memset(m_pp.name, 0, sizeof(m_pp.name));
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname.c_str());
strcpy(name, m_pp.name);
Save();
// Update the active char in account table
database.UpdateLiveChar(in_firstname, AccountID());
// finally, update the /who list
UpdateWho();
// success
ClearNameChange();
return true;
}
@@ -4737,6 +4756,57 @@ bool Client::KeyRingRemove(uint32 item_id)
);
}
bool Client::IsNameChangeAllowed() {
if (RuleB(Character, AlwaysAllowNameChange)) {
return true;
}
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
auto b = DataBucket::GetData(k);
if (!b.value.empty()) {
return true;
}
return false;
}
bool Client::ClearNameChange() {
if (!IsNameChangeAllowed()) {
return false;
}
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
DataBucket::DeleteData(k);
return true;
}
void Client::InvokeChangeNameWindow(bool immediate) {
if (!IsNameChangeAllowed()) {
return;
}
auto packet_op = immediate ? OP_InvokeNameChangeImmediate : OP_InvokeNameChangeLazy;
auto outapp = new EQApplicationPacket(packet_op, 0);
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::GrantNameChange() {
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
k.value = "allowed"; // potentially put a timestamp here
DataBucket::SetData(k);
InvokeChangeNameWindow(true);
}
bool Client::IsPetNameChangeAllowed() {
if (RuleB(Pets, AlwaysAllowPetRename)) {
return true;
+6 -1
View File
@@ -332,6 +332,10 @@ public:
bool KeyRingClear();
bool KeyRingRemove(uint32 item_id);
void KeyRingList();
bool IsNameChangeAllowed();
void InvokeChangeNameWindow(bool immediate = true);
bool ClearNameChange();
void GrantNameChange();
bool IsPetNameChangeAllowed();
void GrantPetNameChange();
void ClearPetNameChange();
@@ -511,7 +515,8 @@ public:
bool AutoAttackEnabled() const { return auto_attack; }
bool AutoFireEnabled() const { return auto_fire; }
bool ChangeFirstName(const char* in_firstname,const char* gmname);
bool ChangeFirstName(const std::string in_firstname,const std::string gmname);
bool ChangeFirstName(const std::string in_firstname);
void Duck();
void Stand();
+23 -4
View File
@@ -826,6 +826,10 @@ void Client::CompleteConnect()
if (IsPetNameChangeAllowed() && !RuleB(Pets, AlwaysAllowPetRename)) {
InvokeChangePetName(false);
}
if (IsNameChangeAllowed() && !RuleB(Character, AlwaysAllowNameChange)) {
InvokeChangeNameWindow(false);
}
}
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
@@ -4256,7 +4260,7 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
else {
OnDisconnect(true);
}
return;
}
@@ -4548,14 +4552,14 @@ void Client::Handle_OP_ChangePetName(const EQApplicationPacket *app) {
auto p = (ChangePetName_Struct *) app->pBuffer;
if (!IsPetNameChangeAllowed()) {
p->response_code = ChangePetNameResponse::NotEligible;
p->response_code = ChangeNameResponse::Ineligible;
QueuePacket(app);
return;
}
p->response_code = ChangePetNameResponse::Denied;
p->response_code = ChangeNameResponse::Denied;
if (ChangePetName(p->new_pet_name)) {
p->response_code = ChangePetNameResponse::Accepted;
p->response_code = ChangeNameResponse::Accepted;
}
QueuePacket(app);
@@ -6776,6 +6780,21 @@ void Client::Handle_OP_GMLastName(const EQApplicationPacket *app)
void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
{
if (app->size == sizeof(AltChangeName_Struct)) {
auto p = (AltChangeName_Struct *) app->pBuffer;
if (!IsNameChangeAllowed()) {
p->response_code = ChangeNameResponse::Ineligible;
QueuePacket(app);
return;
}
p->response_code = ChangeFirstName(p->new_name) ? ChangeNameResponse::Accepted : ChangeNameResponse::Denied;
QueuePacket(app);
return;
}
if (app->size != sizeof(GMName_Struct)) {
LogError("Wrong size: OP_GMNameChange, size=[{}], expected [{}]", app->size, sizeof(GMName_Struct));
return;
+2 -6
View File
@@ -14,7 +14,7 @@ void SetName(Client *c, const Seperator *sep)
std::string new_name = sep->arg[2];
std::string old_name = t->GetCleanName();
if (t->ChangeFirstName(new_name.c_str(), c->GetCleanName())) {
if (t->ChangeFirstName(new_name, c->GetCleanName())) {
c->Message(
Chat::White,
fmt::format(
@@ -24,17 +24,13 @@ void SetName(Client *c, const Seperator *sep)
).c_str()
);
c->Message(Chat::White, "Sending player to char select.");
t->Kick("Name was changed");
return;
}
c->Message(
Chat::White,
fmt::format(
"Unable to rename {}. Check that the new name '{}' isn't already taken.",
"Unable to rename {}. Check that the new name '{}' isn't already taken (Including Pet Names), or isn't invalid",
old_name,
new_name
).c_str()
+21
View File
@@ -3496,6 +3496,24 @@ std::string Lua_Client::GetAccountBucketRemaining(std::string bucket_name)
return self->GetAccountBucketRemaining(bucket_name);
}
void Lua_Client::GrantNameChange()
{
Lua_Safe_Call_Void();
self->GrantNameChange();
}
bool Lua_Client::IsNameChangeAllowed()
{
Lua_Safe_Call_Bool();
return self->IsNameChangeAllowed();
}
bool Lua_Client::ClearNameChange()
{
Lua_Safe_Call_Bool();
return self->ClearNameChange();
}
std::string Lua_Client::GetBandolierName(uint8 bandolier_slot)
{
Lua_Safe_Call_String();
@@ -3635,6 +3653,7 @@ luabind::scope lua_register_client() {
.def("CashReward", &Lua_Client::CashReward)
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
.def("GrantPetNameChange", &Lua_Client::GrantPetNameChange)
.def("ClearNameChange", &Lua_Client::ClearNameChange)
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill)
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill)
@@ -3851,6 +3870,7 @@ luabind::scope lua_register_client() {
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8,bool))&Lua_Client::GrantAllAAPoints)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantNameChange", &Lua_Client::GrantNameChange)
.def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID)
.def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank)
.def("HasAugmentEquippedByID", (bool(Lua_Client::*)(uint32))&Lua_Client::HasAugmentEquippedByID)
@@ -3881,6 +3901,7 @@ luabind::scope lua_register_client() {
.def("IsInAGuild", (bool(Lua_Client::*)(void))&Lua_Client::IsInAGuild)
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
.def("IsMedding", (bool(Lua_Client::*)(void))&Lua_Client::IsMedding)
.def("IsNameChangeAllowed", &Lua_Client::IsNameChangeAllowed)
.def("IsRaidGrouped", (bool(Lua_Client::*)(void))&Lua_Client::IsRaidGrouped)
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)
+4
View File
@@ -609,6 +609,10 @@ public:
void ShowZoneShardMenu();
void GrantPetNameChange();
void GrantNameChange();
bool IsNameChangeAllowed();
bool ClearNameChange();
Lua_Expedition CreateExpedition(luabind::object expedition_info);
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages);
+18
View File
@@ -3261,6 +3261,21 @@ std::string Perl_Client_GetAccountBucketRemaining(Client* self, std::string buck
return self->GetAccountBucketRemaining(bucket_name);
}
void Perl_Client_GrantNameChange(Client* self)
{
self->GrantNameChange();
}
bool Perl_Client_IsNameChangeAllowed(Client* self)
{
return self->IsNameChangeAllowed();
}
bool Perl_Client_ClearNameChange(Client* self)
{
return self->ClearNameChange();
}
std::string Perl_Client_GetBandolierName(Client* self, uint8 bandolier_slot)
{
return self->GetBandolierName(bandolier_slot);
@@ -3393,6 +3408,7 @@ void perl_register_client()
package.add("CashReward", &Perl_Client_CashReward);
package.add("ChangeLastName", &Perl_Client_ChangeLastName);
package.add("GrantPetNameChange", &Perl_Client_GrantPetNameChange);
package.add("ClearNameChange", (bool(*)(Client*))&Perl_Client_ClearNameChange);
package.add("CharacterID", &Perl_Client_CharacterID);
package.add("CheckIncreaseSkill", (bool(*)(Client*, int))&Perl_Client_CheckIncreaseSkill);
package.add("CheckIncreaseSkill", (bool(*)(Client*, int, int))&Perl_Client_CheckIncreaseSkill);
@@ -3607,6 +3623,7 @@ void perl_register_client()
package.add("GrantAllAAPoints", (void(*)(Client*, uint8, bool))&Perl_Client_GrantAllAAPoints);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GrantNameChange", (void(*)(Client*))&Perl_Client_GrantNameChange);
package.add("GuildID", &Perl_Client_GuildID);
package.add("GuildRank", &Perl_Client_GuildRank);
package.add("HasAugmentEquippedByID", &Perl_Client_HasAugmentEquippedByID);
@@ -3637,6 +3654,7 @@ void perl_register_client()
package.add("IsInAGuild", &Perl_Client_IsInAGuild);
package.add("IsLD", &Perl_Client_IsLD);
package.add("IsMedding", &Perl_Client_IsMedding);
package.add("IsNameChangeAllowed", (bool(*)(Client*))&Perl_Client_IsNameChangeAllowed);
package.add("IsRaidGrouped", &Perl_Client_IsRaidGrouped);
package.add("IsSitting", &Perl_Client_IsSitting);
package.add("IsStanding", &Perl_Client_IsStanding);
+2 -3
View File
@@ -1310,15 +1310,14 @@ void QuestManager::rename(std::string name) {
QuestManagerCurrentQuestVars();
if (initiator) {
std::string current_name = initiator->GetName();
if (initiator->ChangeFirstName(name.c_str(), current_name.c_str())) {
if (initiator->ChangeFirstName(name)) {
initiator->Message(
Chat::White,
fmt::format(
"Successfully renamed to {}, kicking to character select.",
"Successfully renamed to {}.",
name
).c_str()
);
initiator->Kick("Name was changed.");
} else {
initiator->Message(
Chat::Red,