From c09a3a5bba123890b1959563ecfc368d09a62250 Mon Sep 17 00:00:00 2001 From: Alex King <89047260+Kinglykrab@users.noreply.github.com> Date: Sun, 28 Jan 2024 21:24:33 -0500 Subject: [PATCH] [Spawn2] Convert Spawn2 Methods to Repositories (#4014) * [Spawn2] Convert Spawn2 Methods to Repositories # Notes - Convert `CreateSpawn2()`, `GetCondition()`, `LoadSpawnConditions()`, `LoadSpawnEvent()`, `UpdateSpawnCondition()`, and `UpdateSpawnEvent()` to repositories. # Images * Update spawn2.cpp --- zone/spawn2.cpp | 415 ++++++++++++++++++++++++++---------------------- zone/spawn2.h | 10 +- zone/zonedb.h | 2 +- 3 files changed, 232 insertions(+), 195 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index cb645cfde..67862185a 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -27,6 +27,9 @@ #include "zone.h" #include "zonedb.h" #include "../common/repositories/criteria/content_filter_criteria.h" +#include "../common/repositories/spawn_conditions_repository.h" +#include "../common/repositories/spawn_condition_values_repository.h" +#include "../common/repositories/spawn_events_repository.h" #include "../common/repositories/spawn2_repository.h" #include "../common/repositories/spawn2_disabled_repository.h" #include "../common/repositories/respawn_times_repository.h" @@ -539,23 +542,31 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spa return true; } -bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value) +bool ZoneDatabase::CreateSpawn2( + Client* c, + uint32 spawngroup_id, + const std::string& zone_short_name, + const glm::vec4& position, + uint32 respawn, + uint32 variance, + uint16 condition, + int16 condition_value +) { + auto e = Spawn2Repository::NewEntity(); - std::string query = StringFormat("INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, " - "respawntime, variance, _condition, cond_value) " - "VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)", - spawngroup, zone, position.x, position.y, position.z, position.w, - respawn, variance, condition, cond_value); - auto results = QueryDatabase(query); - if (!results.Success()) { - return false; - } + e.spawngroupID = spawngroup_id; + e.zone = zone_short_name; + e.x = position.x; + e.y = position.y; + e.z = position.z; + e.heading = position.w; + e.respawntime = respawn; + e.variance = variance; + e._condition = condition; + e.cond_value = condition_value; - if (results.RowsAffected() != 1) - return false; - - return true; + return Spawn2Repository::InsertOne(*this, e).id; } uint32 Zone::CountSpawn2() { @@ -718,7 +729,7 @@ void SpawnConditionManager::Process() { EQTime::ToString(&cevent.next, t); LogSpawns("Event [{}]: Will trigger again in [{}] EQ minutes at [{}]", cevent.id, cevent.period, t.c_str()); //save the next event time in the DB - UpdateDBEvent(cevent); + UpdateSpawnEvent(cevent); //find the next closest event timer. FindNearestEvent(); //minor optimization, if theres no more possible events, @@ -786,147 +797,175 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) { cond.value = new_value; } -void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) { +void SpawnConditionManager::UpdateSpawnEvent(SpawnEvent &event) +{ + auto e = SpawnEventsRepository::FindOne(database, event.id); - std::string query = StringFormat("UPDATE spawn_events SET " - "next_minute = %d, next_hour = %d, " - "next_day = %d, next_month = %d, " - "next_year = %d, enabled = %d, " - "strict = %d WHERE id = %d", - event.next.minute, event.next.hour, - event.next.day, event.next.month, - event.next.year, event.enabled? 1: 0, - event.strict? 1: 0, event.id); - database.QueryDatabase(query); + e.next_minute = event.next.minute; + e.next_hour = event.next.hour; + e.next_day = event.next.day; + e.next_month = event.next.month; + e.next_year = event.next.year; + e.enabled = event.enabled ? 1 : 0; + e.next_minute = event.strict; + + SpawnEventsRepository::UpdateOne(database, e); } -void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) { - - std::string query = StringFormat("REPLACE INTO spawn_condition_values " - "(id, value, zone, instance_id) " - "VALUES( %u, %u, '%s', %u)", - cond_id, value, zone_name, instance_id); - database.QueryDatabase(query); +void SpawnConditionManager::UpdateSpawnCondition( + const std::string& zone_short_name, + uint32 instance_id, + uint16 condition, + int16 condition_value +) +{ + SpawnConditionValuesRepository::ReplaceOne( + database, + SpawnConditionValuesRepository::SpawnConditionValues{ + .id = condition, + .value = static_cast(condition_value), + .zone = zone_short_name, + .instance_id = instance_id + } + ); } -bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) { +bool SpawnConditionManager::LoadSpawnEvent( + uint32 event_id, + SpawnEvent& event, + std::string& zone_short_name +) +{ + const auto& e = SpawnEventsRepository::FindOne(database, event_id); - std::string query = StringFormat("SELECT id, cond_id, period, " - "next_minute, next_hour, next_day, " - "next_month, next_year, enabled, " - "action, argument, strict, zone " - "FROM spawn_events WHERE id = %d", event_id); - auto results = database.QueryDatabase(query); - if (!results.Success()) { + if (!e.id) { return false; } - if (results.RowCount() == 0) - return false; + event.id = e.id; + event.condition_id = e.cond_id; + event.period = e.period; + event.next.minute = e.next_minute; + event.next.hour = e.next_hour; + event.next.day = e.next_day; + event.next.month = e.next_month; + event.next.year = e.next_year; + event.enabled = e.enabled; + event.action = static_cast(e.action); + event.argument = e.argument; + event.strict = e.strict; - auto row = results.begin(); + zone_short_name = e.zone; - event.id = Strings::ToInt(row[0]); - event.condition_id = Strings::ToInt(row[1]); - event.period = Strings::ToInt(row[2]); + std::string time_string; + EQTime::ToString(&event.next, time_string); - event.next.minute = Strings::ToInt(row[3]); - event.next.hour = Strings::ToInt(row[4]); - event.next.day = Strings::ToInt(row[5]); - event.next.month = Strings::ToInt(row[6]); - event.next.year = Strings::ToInt(row[7]); - - event.enabled = Strings::ToInt(row[8]) != 0; - event.action = (SpawnEvent::Action) Strings::ToInt(row[9]); - event.argument = Strings::ToInt(row[10]); - event.strict = Strings::ToInt(row[11]) != 0; - zone_name = row[12]; - - std::string timeAsString; - EQTime::ToString(&event.next, timeAsString); - - LogSpawns("(LoadDBEvent) Loaded [{}] spawn event [{}] on condition [{}] with period [{}] action [{}] argument [{}] strict [{}]. Will trigger at [{}]", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, timeAsString.c_str()); + LogSpawns( + "Loaded [{}] event_id [{}] condition [{}] period [{}] action [{}] argument [{}] strict [{}] time [{}]", + event.enabled ? "enabled" : "disabled", + event.id, + event.condition_id, + event.period, + event.action, + event.argument, + event.strict, + time_string + ); return true; } -bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) +bool SpawnConditionManager::LoadSpawnConditions(const std::string& zone_short_name, uint32 instance_id) { - //clear out old stuff.. spawn_conditions.clear(); - std::string query = StringFormat("SELECT id, onchange, value " - "FROM spawn_conditions " - "WHERE zone = '%s'", zone_name); - auto results = content_db.QueryDatabase(query); - if (!results.Success()) { + const auto& conditions = SpawnConditionsRepository::GetWhere( + content_db, + fmt::format( + "`zone` = '{}'", + Strings::Escape(zone_short_name) + ) + ); + + if (conditions.empty()) { return false; - } + } - for (auto row = results.begin(); row != results.end(); ++row) { - //load spawn conditions - SpawnCondition cond; + for (const auto& e : conditions) { + SpawnCondition c; - cond.condition_id = Strings::ToInt(row[0]); - cond.value = Strings::ToInt(row[2]); - cond.on_change = (SpawnCondition::OnChange) Strings::ToInt(row[1]); - spawn_conditions[cond.condition_id] = cond; + c.condition_id = e.id; + c.value = e.value; + c.on_change = static_cast(e.onchange); - LogSpawns("Loaded spawn condition [{}] with value [{}] and on_change [{}]", cond.condition_id, cond.value, cond.on_change); - } + spawn_conditions[c.condition_id] = c; - LogInfo("Loaded [{}] spawn_conditions", Strings::Commify(std::to_string(results.RowCount()))); + LogSpawns( + "Loaded spawn condition [{}] with value [{}] and on_change [{}]", + c.condition_id, + c.value, + c.on_change + ); + } - //load values - query = StringFormat("SELECT id, value FROM spawn_condition_values " - "WHERE zone = '%s' AND instance_id = %u", - zone_name, instance_id); - results = database.QueryDatabase(query); - if (!results.Success()) { + LogInfo("Loaded [{}] spawn_conditions", Strings::Commify(std::to_string(conditions.size()))); + + const auto& condition_values = SpawnConditionValuesRepository::GetWhere( + database, + fmt::format( + "`zone` = '{}' AND `instance_id` = {}", + Strings::Escape(zone_short_name), + instance_id + ) + ); + + if (condition_values.empty()) { spawn_conditions.clear(); return false; - } + } - for (auto row = results.begin(); row != results.end(); ++row) { - auto iter = spawn_conditions.find(Strings::ToInt(row[0])); + for (const auto& e : condition_values) { + auto i = spawn_conditions.find(e.id); + if (i != spawn_conditions.end()) { + i->second.value = e.value; + } + } - if(iter != spawn_conditions.end()) - iter->second.value = Strings::ToInt(row[1]); - } + const auto& events = SpawnEventsRepository::GetWhere( + database, + fmt::format( + "`zone` = '{}'", + Strings::Escape(zone_short_name) + ) + ); - //load spawn events - query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, " - "next_day, next_month, next_year, enabled, action, argument, strict " - "FROM spawn_events WHERE zone = '%s'", zone_name); - results = database.QueryDatabase(query); - if (!results.Success()) { + if (events.empty()) { return false; - } + } - LogInfo("Loaded [{}] spawn_events", Strings::Commify(std::to_string(results.RowCount()))); + LogInfo("Loaded [{}] spawn_events", Strings::Commify(std::to_string(events.size()))); - for (auto row = results.begin(); row != results.end(); ++row) { + for (const auto& e : events) { SpawnEvent event; - event.id = Strings::ToInt(row[0]); - event.condition_id = Strings::ToInt(row[1]); - event.period = Strings::ToInt(row[2]); + event.id = e.id; + event.condition_id = e.cond_id; + event.period = e.period; - if (event.period == 0) { + if (!event.period) { LogError("Refusing to load spawn event #[{}] because it has a period of 0\n", event.id); continue; } - event.next.minute = Strings::ToInt(row[3]); - event.next.hour = Strings::ToInt(row[4]); - event.next.day = Strings::ToInt(row[5]); - event.next.month = Strings::ToInt(row[6]); - event.next.year = Strings::ToInt(row[7]); - - event.enabled = Strings::ToInt(row[8]) == 0 ? false : true; - event.action = (SpawnEvent::Action) Strings::ToInt(row[9]); - event.argument = Strings::ToInt(row[10]); - event.strict = Strings::ToInt(row[11]) == 0 ? false : true; + event.next.minute = e.next_minute; + event.next.hour = e.next_hour; + event.next.day = e.next_day; + event.next.month = e.next_month; + event.next.year = e.next_year; + event.enabled = e.enabled; + event.action = static_cast(e.action); + event.argument = e.argument; + event.strict = e.strict; spawn_events.push_back(event); @@ -945,68 +984,70 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in //now we need to catch up on events that happened while we were away //and use them to alter just the condition variables. - //each spawn2 will then use its correct condition value when - //it decides what to do. This essentially forces a 'depop' action - //on spawn points which are turned off, and a 'repop' action on - //spawn points which get turned on. Im too lazy to figure out a - //better solution, and I just dont care thats much. //get our current time TimeOfDay_Struct tod{}; zone->zone_time.GetCurrentEQTimeOfDay(&tod); - for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) { - SpawnEvent &cevent = *cur; + for (auto& e : spawn_events) { + bool is_strict = false; - bool StrictCheck = false; - if(cevent.strict && - cevent.next.hour == tod.hour && - cevent.next.day == tod.day && - cevent.next.month == tod.month && - cevent.next.year == tod.year) - StrictCheck = true; + if ( + e.strict && + e.next.hour == tod.hour && + e.next.day == tod.day && + e.next.month == tod.month && + e.next.year == tod.year + ) { + is_strict = true; + } //If event is disabled, or we failed the strict check, set initial spawn_condition to default startup value from spawn_conditions. - if(!cevent.enabled || !StrictCheck) { + if (!e.enabled || !is_strict) { SetCondition( - zone->GetShortName(), - zone->GetInstanceID(), - cevent.condition_id, - spawn_conditions[cevent.condition_id].value + zone->GetShortName(), + zone->GetInstanceID(), + e.condition_id, + spawn_conditions[e.condition_id].value ); } - if(!cevent.enabled) - continue; + if (!e.enabled) { + continue; + } //watch for special case of all 0s, which means to reset next to now - if (cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && - cevent.next.minute == 0) { - LogSpawns("Initial next trigger time set for spawn event [{}]", cevent.id); - memcpy(&cevent.next, &tod, sizeof(cevent.next)); - //add one period - EQTime::AddMinutes(cevent.period, &cevent.next); - //save it in the db. - UpdateDBEvent(cevent); - continue; //were done with this event. + if ( + e.next.year == 0 && + e.next.month == 0 && + e.next.day == 0 && + e.next.hour == 0 && + e.next.minute == 0 + ) { + LogSpawns("Initial next trigger time set for spawn event [{}]", e.id); + memcpy(&e.next, &tod, sizeof(e.next)); + EQTime::AddMinutes(e.period, &e.next); + UpdateSpawnEvent(e); + continue; } bool ran = false; - while (EQTime::IsTimeBefore(&tod, &cevent.next)) { - LogSpawns("Catch up triggering on event [{}]", cevent.id); + while (EQTime::IsTimeBefore(&tod, &e.next)) { + LogSpawns("Catch up triggering on event [{}]", e.id); //this event has been triggered. //execute the event - if (!cevent.strict || StrictCheck) { - ExecEvent(cevent, false); + if (!e.strict || is_strict) { + ExecEvent(e, false); } //add the period of the event to the trigger time - EQTime::AddMinutes(cevent.period, &cevent.next); + EQTime::AddMinutes(e.period, &e.next); ran = true; } //only write it out if the event actually ran - if(ran) - UpdateDBEvent(cevent); //save the event in the DB + if (ran) { + UpdateSpawnEvent(e); + } } //now our event timers are all up to date, find our closest event. @@ -1095,7 +1136,7 @@ void SpawnConditionManager::SetCondition(const char *zone_short, uint32 instance //set our local value cond.value = new_value; //save it in the DB too - UpdateDBCondition(zone_short, instance_id, condition_id, new_value); + UpdateSpawnCondition(zone_short, instance_id, condition_id, new_value); LogSpawns("Local Condition update requested for [{}] with value [{}]", condition_id, new_value); @@ -1109,7 +1150,7 @@ void SpawnConditionManager::SetCondition(const char *zone_short, uint32 instance LogSpawns("Remote spawn condition [{}] set to [{}]. Updating DB and notifying world", condition_id, new_value); - UpdateDBCondition(zone_short, instance_id, condition_id, new_value); + UpdateSpawnCondition(zone_short, instance_id, condition_id, new_value); auto pack = new ServerPacket(ServerOP_SpawnCondition, sizeof(ServerSpawnCondition_Struct)); ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer; @@ -1138,7 +1179,7 @@ void SpawnConditionManager::ReloadEvent(uint32 event_id) { if(cevent.id == event_id) { //load the event into the old event slot - if(!LoadDBEvent(event_id, cevent, zone_short_name)) { + if(!LoadSpawnEvent(event_id, cevent, zone_short_name)) { //unable to find the event in the database... LogSpawns("Failed to reload event [{}] from the database", event_id); return; @@ -1151,7 +1192,7 @@ void SpawnConditionManager::ReloadEvent(uint32 event_id) { //if we get here, it is a new event... SpawnEvent e; - if(!LoadDBEvent(event_id, e, zone_short_name)) { + if(!LoadSpawnEvent(event_id, e, zone_short_name)) { //unable to find the event in the database... LogSpawns("Failed to reload event [{}] from the database", event_id); return; @@ -1195,7 +1236,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri } //save the event in the DB - UpdateDBEvent(cevent); + UpdateSpawnEvent(cevent); //sync up our nearest event FindNearestEvent(); @@ -1218,7 +1259,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri //update its in-memory event list SpawnEvent e; std::string zone_short_name; - if(!LoadDBEvent(event_id, e, zone_short_name)) { + if(!LoadSpawnEvent(event_id, e, zone_short_name)) { LogSpawns("Unable to find spawn event [{}] in the database", event_id); //unable to find the event in the database... return; @@ -1239,7 +1280,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri LogSpawns("Spawn event [{}] is in zone [{}]. State changed. Notifying world", event_id, zone_short_name.c_str(), e.period); } //save the event in the DB - UpdateDBEvent(e); + UpdateSpawnEvent(e); //now notify the zone @@ -1253,43 +1294,39 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri safe_delete(pack); } -int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instance_id, uint16 condition_id) { - if(!strcasecmp(zone_short, zone->GetShortName()) && instance_id == zone->GetInstanceID()) - { - //this is a local spawn condition - std::map::iterator condi; - condi = spawn_conditions.find(condition_id); - if(condi == spawn_conditions.end()) - { - LogSpawns("Unable to find local condition [{}] in Get request", condition_id); - return(0); //unable to find the spawn condition +int16 SpawnConditionManager::GetCondition(const std::string& zone_short_name, uint32 instance_id, uint16 condition) +{ + if ( + Strings::EqualFold(zone_short_name, zone->GetShortName()) && + instance_id == zone->GetInstanceID() + ) { + auto i = spawn_conditions.find(condition); + if (i == spawn_conditions.end()) { + LogSpawns("Unable to find local condition [{}] in Get request", condition); + return (0); //unable to find the spawn condition } - SpawnCondition &cond = condi->second; - return cond.value; + return i->second.value; } - //this is a remote spawn condition, grab it from the DB - //load spawn conditions - std::string query = StringFormat( - "SELECT value FROM spawn_condition_values " - "WHERE zone = '%s' AND instance_id = %u AND id = %d", - zone_short, instance_id, condition_id + const auto& l = SpawnConditionValuesRepository::GetWhere( + database, + fmt::format( + "`zone` = '{}' AND `instance_id` = {} AND `id` = {}", + Strings::Escape(zone_short_name), + instance_id, + condition + ) ); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - LogSpawns("Unable to query remote condition [{}] from zone [{}] in Get request", condition_id, zone_short); - return 0; //dunno a better thing to do... + + if (l.empty()) { + LogSpawns("Unable to query remote condition [{}] from zone [{}] in Get request", condition, zone_short_name); + return 0; } - if (results.RowCount() == 0) { - LogSpawns("Unable to load remote condition [{}] from zone [{}] in Get request", condition_id, zone_short); - return 0; //dunno a better thing to do... - } + const auto& e = l.front(); - auto row = results.begin(); - - return Strings::ToInt(row[0]); + return e.value; } bool SpawnConditionManager::Check(uint16 condition, int16 min_value) { diff --git a/zone/spawn2.h b/zone/spawn2.h index c6d5d0c46..6d0ce9a0e 100644 --- a/zone/spawn2.h +++ b/zone/spawn2.h @@ -147,9 +147,9 @@ public: SpawnConditionManager(); void Process(); - bool LoadSpawnConditions(const char* zone_name, uint32 instance_id); + bool LoadSpawnConditions(const std::string& zone_short_name, uint32 instance_id); - int16 GetCondition(const char *zone_short, uint32 instance_id, uint16 condition_id); + int16 GetCondition(const std::string& zone_short_name, uint32 instance_id, uint16 condition); void SetCondition(const char *zone_short, uint32 instance_id, uint16 condition_id, int16 new_value, bool world_update = false); void ToggleEvent(uint32 event_id, bool enabled, bool strict, bool reset_base); bool Check(uint16 condition, int16 min_value); @@ -160,9 +160,9 @@ protected: std::vector spawn_events; void ExecEvent(SpawnEvent &e, bool send_update); - void UpdateDBEvent(SpawnEvent &e); - bool LoadDBEvent(uint32 event_id, SpawnEvent &e, std::string &zone_name); - void UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value); + void UpdateSpawnEvent(SpawnEvent &e); + bool LoadSpawnEvent(uint32 event_id, SpawnEvent& event, std::string& zone_short_name); + void UpdateSpawnCondition(const std::string& zone_short_name, uint32 instance_id, uint16 condition, int16 condition_value); void FindNearestEvent(); Timer minute_timer; diff --git a/zone/zonedb.h b/zone/zonedb.h index 3484cfe54..accab1868 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -530,7 +530,7 @@ public: bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); bool LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version); - bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); + bool CreateSpawn2(Client* c, uint32 spawngroup_id, const std::string& zone_short_name, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 condition_value); void UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id,uint32 timeleft); uint32 GetSpawnTimeLeft(uint32 spawn2_id, uint16 instance_id); void UpdateSpawn2Status(uint32 id, uint8 new_status, uint32 instance_id);