[Zone] Zone State Improvements (Continued) (#4768)

* [Zone] Zone State Improvements (Continued)

* Ignore a few events when we resume from suspend

* Add is_zone field

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update zone_save_state.cpp

* Update zone_save_state.cpp

* Add Zone Variables

* Update methods

* Update zone_save_state.cpp

* Update zone_save_state.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
Chris Miles
2025-03-11 01:14:09 -05:00
committed by GitHub
parent 051ce3736f
commit 30c39194a3
10 changed files with 377 additions and 103 deletions
+53 -1
View File
@@ -727,6 +727,52 @@ std::string Lua_Zone::GetBucketRemaining(const std::string& bucket_name)
return self->GetBucketRemaining(bucket_name);
}
void Lua_Zone::ClearVariables()
{
Lua_Safe_Call_Void();
self->ClearVariables();
}
bool Lua_Zone::DeleteVariable(const std::string& variable_name)
{
Lua_Safe_Call_Bool();
return self->DeleteVariable(variable_name);
}
std::string Lua_Zone::GetVariable(const std::string& variable_name)
{
Lua_Safe_Call_String();
return self->GetVariable(variable_name);
}
luabind::object Lua_Zone::GetVariables(lua_State* L)
{
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = self->GetVariables();
int i = 1;
for (const auto& v : l) {
t[i] = v;
i++;
}
}
return t;
}
void Lua_Zone::SetVariable(const std::string& variable_name, const std::string& variable_value)
{
Lua_Safe_Call_Void();
self->SetVariable(variable_name, variable_value);
}
bool Lua_Zone::VariableExists(const std::string& variable_name)
{
Lua_Safe_Call_Bool();
return self->VariableExists(variable_name);
}
luabind::scope lua_register_zone() {
return luabind::class_<Lua_Zone>("Zones")
.def(luabind::constructor<>())
@@ -737,7 +783,9 @@ luabind::scope lua_register_zone() {
.def("CanDoCombat", &Lua_Zone::CanDoCombat)
.def("CanLevitate", &Lua_Zone::CanLevitate)
.def("ClearSpawnTimers", &Lua_Zone::ClearSpawnTimers)
.def("ClearVariables", &Lua_Zone::ClearVariables)
.def("DeleteBucket", (void(Lua_Zone::*)(const std::string&))&Lua_Zone::DeleteBucket)
.def("DeleteVariable", &Lua_Zone::DeleteVariable)
.def("Depop", (void(Lua_Zone::*)(void))&Lua_Zone::Depop)
.def("Depop", (void(Lua_Zone::*)(bool))&Lua_Zone::Depop)
.def("Despawn", &Lua_Zone::Despawn)
@@ -819,6 +867,8 @@ luabind::scope lua_register_zone() {
.def("GetZoneType", &Lua_Zone::GetZoneType)
.def("GetUnderworld", &Lua_Zone::GetUnderworld)
.def("GetUnderworldTeleportIndex", &Lua_Zone::GetUnderworldTeleportIndex)
.def("GetVariable", &Lua_Zone::GetVariable)
.def("GetVariables", &Lua_Zone::GetVariables)
.def("GetWalkSpeed", &Lua_Zone::GetWalkSpeed)
.def("GetZoneZType", &Lua_Zone::GetZoneZType)
.def("GetZoneTotalBlockedSpells", &Lua_Zone::GetZoneTotalBlockedSpells)
@@ -849,6 +899,8 @@ luabind::scope lua_register_zone() {
.def("SetInstanceTimer", &Lua_Zone::SetInstanceTimer)
.def("SetInstanceTimeRemaining", &Lua_Zone::SetInstanceTimeRemaining)
.def("SetIsHotzone", &Lua_Zone::SetIsHotzone)
.def("ShowZoneGlobalLoot", &Lua_Zone::ShowZoneGlobalLoot);
.def("SetVariable", &Lua_Zone::SetVariable)
.def("ShowZoneGlobalLoot", &Lua_Zone::ShowZoneGlobalLoot)
.def("VariableExists", &Lua_Zone::VariableExists);
}
+6
View File
@@ -141,6 +141,12 @@ public:
void SetInstanceTimeRemaining(uint32 time_remaining);
void SetIsHotzone(bool is_hotzone);
void ShowZoneGlobalLoot(Lua_Client c);
void ClearVariables();
bool DeleteVariable(const std::string& variable_name);
std::string GetVariable(const std::string& variable_name);
luabind::object GetVariables(lua_State* L);
void SetVariable(const std::string& variable_name, const std::string& variable_value);
bool VariableExists(const std::string& variable_name);
// data buckets
void SetBucket(const std::string& bucket_name, const std::string& bucket_value);
+43
View File
@@ -561,6 +561,43 @@ std::string Perl_Zone_GetBucketRemaining(Zone* self, const std::string bucket_na
return self->GetBucketRemaining(bucket_name);
}
void Perl_Zone_ClearVariables(Zone* self)
{
self->ClearVariables();
}
bool Perl_Zone_DeleteVariable(Zone* self, const std::string variable_name)
{
return self->DeleteVariable(variable_name);
}
std::string Perl_Zone_GetVariable(Zone* self, const std::string variable_name)
{
return self->GetVariable(variable_name);
}
perl::array Perl_Zone_GetVariables(Zone* self)
{
perl::array a;
const auto& l = self->GetVariables();
for (const auto& v : l) {
a.push_back(v);
}
return a;
}
void Perl_Zone_SetVariable(Zone* self, const std::string variable_name, const std::string variable_value)
{
self->SetVariable(variable_name, variable_value);
}
bool Perl_Zone_VariableExists(Zone* self, const std::string variable_name)
{
return self->VariableExists(variable_name);
}
void perl_register_zone()
{
perl::interpreter perl(PERL_GET_THX);
@@ -573,7 +610,9 @@ void perl_register_zone()
package.add("CanDoCombat", &Perl_Zone_CanDoCombat);
package.add("CanLevitate", &Perl_Zone_CanLevitate);
package.add("ClearSpawnTimers", &Perl_Zone_ClearSpawnTimers);
package.add("ClearVariables", &Perl_Zone_ClearVariables);
package.add("DeleteBucket", &Perl_Zone_DeleteBucket);
package.add("DeleteVariable", &Perl_Zone_DeleteVariable);
package.add("Depop", (void(*)(Zone*))&Perl_Zone_Depop);
package.add("Depop", (void(*)(Zone*, bool))&Perl_Zone_Depop);
package.add("Despawn", &Perl_Zone_Despawn);
@@ -655,6 +694,8 @@ void perl_register_zone()
package.add("GetZoneType", &Perl_Zone_GetZoneType);
package.add("GetUnderworld", &Perl_Zone_GetUnderworld);
package.add("GetUnderworldTeleportIndex", &Perl_Zone_GetUnderworldTeleportIndex);
package.add("GetVariable", &Perl_Zone_GetVariable);
package.add("GetVariables", &Perl_Zone_GetVariables);
package.add("GetWalkSpeed", &Perl_Zone_GetWalkSpeed);
package.add("GetZoneZType", &Perl_Zone_GetZoneZType);
package.add("GetZoneTotalBlockedSpells", &Perl_Zone_GetZoneTotalBlockedSpells);
@@ -685,7 +726,9 @@ void perl_register_zone()
package.add("SetInstanceTimer", &Perl_Zone_SetInstanceTimer);
package.add("SetInstanceTimeRemaining", &Perl_Zone_SetInstanceTimeRemaining);
package.add("SetIsHotzone", &Perl_Zone_SetIsHotzone);
package.add("SetVariable", &Perl_Zone_SetVariable);
package.add("ShowZoneGlobalLoot", &Perl_Zone_ShowZoneGlobalLoot);
package.add("VariableExists", &Perl_Zone_VariableExists);
}
#endif //EMBPERL_XS_CLASSES
+6
View File
@@ -435,6 +435,12 @@ int QuestParserCollection::EventNPC(
std::vector<std::any>* extra_pointers
)
{
if (npc->IsResumedFromZoneSuspend()) {
if (event_id == EVENT_DEATH_COMPLETE || event_id == EVENT_DEATH) {
return 0;
}
}
const int local_return = EventNPCLocal(event_id, npc, init, data, extra_data, extra_pointers);
const int global_return = EventNPCGlobal(event_id, npc, init, data, extra_data, extra_pointers);
const int default_return = DispatchEventNPC(event_id, npc, init, data, extra_data, extra_pointers);
+67
View File
@@ -3218,5 +3218,72 @@ void Zone::DisableRespawnTimers()
}
}
void Zone::ClearVariables()
{
m_zone_variables.clear();
}
bool Zone::DeleteVariable(const std::string& variable_name)
{
if (m_zone_variables.empty() || variable_name.empty()) {
return false;
}
auto v = m_zone_variables.find(variable_name);
if (v == m_zone_variables.end()) {
return false;
}
m_zone_variables.erase(v);
return true;
}
std::string Zone::GetVariable(const std::string& variable_name)
{
if (m_zone_variables.empty() || variable_name.empty()) {
return std::string();
}
const auto& v = m_zone_variables.find(variable_name);
return v != m_zone_variables.end() ? v->second : std::string();
}
std::vector<std::string> Zone::GetVariables()
{
std::vector<std::string> l;
if (m_zone_variables.empty()) {
return l;
}
l.reserve(m_zone_variables.size());
for (const auto& v : m_zone_variables) {
l.emplace_back(v.first);
}
return l;
}
void Zone::SetVariable(const std::string& variable_name, const std::string& variable_value)
{
if (variable_name.empty()) {
return;
}
m_zone_variables[variable_name] = variable_value;
}
bool Zone::VariableExists(const std::string& variable_name)
{
if (m_zone_variables.empty() || variable_name.empty()) {
return false;
}
return m_zone_variables.find(variable_name) != m_zone_variables.end();
}
#include "zone_save_state.cpp"
#include "zone_loot.cpp"
+9
View File
@@ -197,6 +197,13 @@ public:
int32 MobsAggroCount() { return aggroedmobs; }
DynamicZone *GetDynamicZone();
void ClearVariables();
bool DeleteVariable(const std::string& variable_name);
std::string GetVariable(const std::string& variable_name);
std::vector<std::string> GetVariables();
void SetVariable(const std::string& variable_name, const std::string& variable_value);
bool VariableExists(const std::string& variable_name);
IPathfinder *pathing;
std::vector<NPC_Emote_Struct *> npc_emote_list;
LinkedList<Spawn2 *> spawn2_list;
@@ -244,6 +251,8 @@ public:
std::vector<uint32> discovered_items;
std::map<std::string, std::string> m_zone_variables;
time_t weather_timer;
Timer spawn2_timer;
Timer hot_reload_timer;
+71 -4
View File
@@ -291,6 +291,55 @@ inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStat
n->SetResumedFromZoneSuspend(true);
}
inline std::string GetZoneVariablesSerialized(Zone *z)
{
std::map<std::string, std::string> variables;
for (const auto &k: z->GetVariables()) {
variables[k] = z->GetVariable(k);
}
try {
std::ostringstream os;
{
cereal::JSONOutputArchiveSingleLine archive(os);
archive(variables);
}
return os.str();
}
catch (const std::exception &e) {
LogZoneState("Failed to serialize variables for zone [{}]", e.what());
return "";
}
return "";
}
inline void LoadZoneVariables(Zone *z, const std::string &variables)
{
if (!Strings::IsValidJson(variables)) {
LogZoneState("Invalid JSON data for zone [{}]", variables);
return;
}
std::map<std::string, std::string> deserialized_map;
try {
std::istringstream is(variables);
{
cereal::JSONInputArchive archive(is);
archive(deserialized_map);
}
}
catch (const std::exception &e) {
LogZoneState("Failed to load zone variables [{}]", e.what());
return;
}
for (const auto &[key, value]: deserialized_map) {
z->SetVariable(key, value);
}
}
bool Zone::LoadZoneState(
std::unordered_map<uint32, uint32> spawn_times,
std::vector<Spawn2DisabledRepository::Spawn2Disabled> disabled_spawns
@@ -315,11 +364,12 @@ bool Zone::LoadZoneState(
zone->Process();
for (auto &s: spawn_states) {
if (s.spawngroup_id == 0) {
if (s.is_zone) {
LoadZoneVariables(zone, s.entity_variables);
continue;
}
if (s.is_corpse) {
if (s.spawngroup_id == 0 || s.is_corpse || s.is_zone) {
continue;
}
@@ -374,7 +424,7 @@ bool Zone::LoadZoneState(
// dynamic spawns, quest spawns, triggers etc.
for (auto &s: spawn_states) {
if (s.spawngroup_id > 0) {
if (s.spawngroup_id > 0 || s.is_zone) {
continue;
}
@@ -524,7 +574,13 @@ void Zone::SaveZoneState()
bool ignore_npcs =
n.second->GetSpawnGroupId() > 0 ||
n.second->GetNPCTypeID() < 100 ||
n.second->HasOwner();
n.second->GetNPCTypeID() == 500 || // Trap::CreateHiddenTrigger
n.second->IsAura() ||
n.second->IsBot() ||
n.second->IsMerc() ||
n.second->IsTrap() ||
n.second->GetSwarmOwner() ||
n.second->IsPet();
if (ignore_npcs) {
continue;
}
@@ -560,6 +616,17 @@ void Zone::SaveZoneState()
spawns.emplace_back(s);
}
// zone state variables
if (!GetVariables().empty()) {
ZoneStateSpawnsRepository::ZoneStateSpawns z{};
z.zone_id = GetZoneID();
z.instance_id = GetInstanceID();
z.is_zone = 1;
z.entity_variables = GetZoneVariablesSerialized(this);
spawns.emplace_back(z);
}
ZoneStateSpawnsRepository::DeleteWhere(
database,
fmt::format(