[Zone] Zone State Automated Testing and Improvements (#4808)

* [Zone] Zone State Automated Testing and Improvements

* Spawn condition

* Update zone.cpp

* Remove redundant logic

* Update zone_state.cpp

* TestZLocationDrift

* Protect NPC resumed NPC's from being able to die
This commit is contained in:
Chris Miles
2025-03-30 01:45:28 -05:00
committed by GitHub
parent c8a7066d0e
commit b9cfdea76c
23 changed files with 1312 additions and 168 deletions
+13 -60
View File
@@ -4,46 +4,7 @@
#include "npc.h"
#include "corpse.h"
#include "zone.h"
#include "../common/repositories/zone_state_spawns_repository.h"
#include "../common/repositories/spawn2_disabled_repository.h"
struct LootEntryStateData {
uint32 item_id;
uint32_t lootdrop_id;
uint16 charges = 0; // used in dynamically added loot (AddItem)
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(lootdrop_id),
CEREAL_NVP(charges)
);
}
};
struct LootStateData {
uint32 copper = 0;
uint32 silver = 0;
uint32 gold = 0;
uint32 platinum = 0;
std::vector<LootEntryStateData> entries = {};
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum),
CEREAL_NVP(entries)
);
}
};
#include "zone_save_state.h"
// IsZoneStateValid checks if the zone state is valid
// if these fields are all empty or zero value for an entire zone state, it's considered invalid
@@ -359,7 +320,7 @@ inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStat
auto decay_time = s.decay_in_seconds * 1000;
if (decay_time > 0) {
n->SetQueuedToCorpse();
n->SetCorpseDecayTime(decay_time);
entity_list.RestoreCorpse(n, decay_time);
}
else {
n->Depop();
@@ -454,6 +415,7 @@ bool Zone::LoadZoneState(
zone->Process();
// load zone variables first
int count = 0;
for (auto &s: spawn_states) {
if (s.is_zone) {
LoadZoneVariables(zone, s.entity_variables);
@@ -502,11 +464,13 @@ bool Zone::LoadZoneState(
);
if (spawn_time_left == 0) {
new_spawn->SetCurrentNPCID(s.npc_id);
new_spawn->SetResumedNPCID(s.npc_id);
new_spawn->SetResumedFromZoneSuspend(true);
new_spawn->SetEntityVariables(GetVariablesDeserialized(s.entity_variables));
}
count++;
spawn2_list.Insert(new_spawn);
new_spawn->Process();
auto n = new_spawn->GetNPC();
@@ -548,24 +512,6 @@ bool Zone::LoadZoneState(
LoadNPCState(zone, npc, s);
}
// any NPC that is spawned by the spawn system
for (auto &e: entity_list.GetNPCList()) {
auto npc = e.second;
if (npc->GetSpawnGroupId() == 0) {
continue;
}
for (auto &s: spawn_states) {
bool is_same_npc =
s.npc_id == npc->GetNPCTypeID() &&
s.spawn2_id == npc->GetSpawnPointID() &&
s.spawngroup_id == npc->GetSpawnGroupId();
if (is_same_npc) {
LoadNPCState(zone, npc, s);
}
}
}
return !spawn_states.empty();
}
@@ -638,6 +584,7 @@ void Zone::SaveZoneState()
std::vector<ZoneStateSpawnsRepository::ZoneStateSpawns> spawns = {};
LinkedListIterator<Spawn2 *> iterator(spawn2_list);
iterator.Reset();
int count = 0;
while (iterator.MoreElements()) {
Spawn2 *sp = iterator.GetData();
auto s = ZoneStateSpawnsRepository::NewEntity();
@@ -667,6 +614,7 @@ void Zone::SaveZoneState()
spawns.emplace_back(s);
iterator.Advance();
count++;
}
// npc's that are not in the spawn2 list
@@ -742,6 +690,11 @@ void Zone::SaveZoneState()
return;
}
if (spawns.empty()) {
LogInfo("No zone state data to save");
return;
}
ZoneStateSpawnsRepository::InsertMany(database, spawns);
LogInfo("Saved [{}] zone state spawns", Strings::Commify(spawns.size()));