From 43716332aae96c1b4b4fc89a2b04b6e2a8f5ae5a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 30 Mar 2020 05:49:43 -0500 Subject: [PATCH] Bulk load grids at repop and zone init instead of 2 costly individual selects per NPC, create repositories to decouple database logic from business logic --- common/CMakeLists.txt | 2 + common/repositories/grid_entries_repository.h | 126 ++++++++++++++++++ common/repositories/grid_repository.h | 121 +++++++++++++++++ zone/npc.h | 2 +- zone/waypoints.cpp | 71 +++++----- zone/zone.cpp | 9 ++ zone/zone.h | 7 + 7 files changed, 298 insertions(+), 40 deletions(-) create mode 100644 common/repositories/grid_entries_repository.h create mode 100644 common/repositories/grid_repository.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ce62fbb00..df2047ef9 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -197,6 +197,8 @@ SET(common_headers races.h random.h repositories/character_recipe_list_repository.h + repositories/grid_repository.h + repositories/grid_entries_repository.h repositories/tradeskill_recipe_repository.h rdtsc.h rulesys.h diff --git a/common/repositories/grid_entries_repository.h b/common/repositories/grid_entries_repository.h new file mode 100644 index 000000000..0c2e34d85 --- /dev/null +++ b/common/repositories/grid_entries_repository.h @@ -0,0 +1,126 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef EQEMU_GRID_ENTRIES_REPOSITORY_H +#define EQEMU_GRID_ENTRIES_REPOSITORY_H + +#include "../database.h" +#include "../string_util.h" + +class GridEntriesRepository { +public: + struct GridEntry { + int gridid; + int zoneid; + int number; + float x; + float y; + float z; + float heading; + int pause; + int8 centerpoint; + }; + + static std::vector Columns() + { + return { + "gridid", + "zoneid", + "number", + "x", + "y", + "z", + "heading", + "pause", + "centerpoint", + }; + } + + static std::string ColumnsRaw() + { + return std::string(implode(", ", Columns())); + } + + static std::string TableName() + { + return std::string("grid_entries"); + } + + static std::string BaseSelect() + { + return std::string( + fmt::format( + "SELECT {} FROM {}", + ColumnsRaw(), + TableName() + ) + ); + } + + static GridEntry Default() + { + GridEntry entry{}; + + entry.gridid = 0; + entry.zoneid = 0; + entry.number = 0; + entry.x = 0; + entry.y = 0; + entry.z = 0; + entry.heading = 0; + entry.pause = 0; + entry.centerpoint = 0; + + return entry; + } + + static std::vector GetZoneGridEntries(int zone_id) + { + std::vector grid_entries; + + auto results = content_db.QueryDatabase( + fmt::format( + "{} WHERE zoneid = {} ORDER BY gridid, number", + BaseSelect(), + zone_id + ) + ); + + for (auto row = results.begin(); row != results.end(); ++row) { + GridEntry entry{}; + + entry.gridid = atoi(row[0]); + entry.zoneid = atoi(row[1]); + entry.number = atoi(row[2]); + entry.x = atof(row[3]); + entry.y = atof(row[4]); + entry.z = atof(row[5]); + entry.heading = atof(row[6]); + entry.pause = atoi(row[7]); + entry.centerpoint = atoi(row[8]); + + grid_entries.push_back(entry); + } + + return grid_entries; + } +}; + +#endif diff --git a/common/repositories/grid_repository.h b/common/repositories/grid_repository.h new file mode 100644 index 000000000..523c5212d --- /dev/null +++ b/common/repositories/grid_repository.h @@ -0,0 +1,121 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef EQEMU_GRID_REPOSITORY_H +#define EQEMU_GRID_REPOSITORY_H + +#include "../database.h" +#include "../string_util.h" + +class GridRepository { +public: + struct Grid { + int id; + int zoneid; + int type; + int type2; + }; + + static std::vector Columns() + { + return { + "id", + "zoneid", + "type", + "type2", + }; + } + + static std::string ColumnsRaw() + { + return std::string(implode(", ", Columns())); + } + + static std::string TableName() + { + return std::string("grid"); + } + + static std::string BaseSelect() + { + return std::string( + fmt::format( + "SELECT {} FROM {}", + ColumnsRaw(), + TableName() + ) + ); + } + + static Grid Default() + { + Grid entry{}; + + entry.id = 0; + entry.zoneid = 0; + entry.type = 0; + entry.type2 = 0; + + return entry; + } + + static std::vector GetZoneGrids(int zone_id) + { + std::vector grids; + + auto results = content_db.QueryDatabase( + fmt::format( + "{} WHERE zoneid = {}", + BaseSelect(), + zone_id + ) + ); + + for (auto row = results.begin(); row != results.end(); ++row) { + Grid entry{}; + + entry.id = atoi(row[0]); + entry.zoneid = atoi(row[1]); + entry.type = atoi(row[2]); + entry.type2 = atoi(row[3]); + + grids.push_back(entry); + } + + return grids; + } + + static Grid GetGrid( + const std::vector& grids, + int grid_id + ) + { + for (auto &row : grids) { + if (row.id == grid_id) { + return row; + } + } + + return Default(); + } + +}; + +#endif diff --git a/zone/npc.h b/zone/npc.h index 020151028..7c108b4b7 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -303,7 +303,7 @@ public: int GetMaxWp() const { return max_wp; } void DisplayWaypointInfo(Client *to); void CalculateNewWaypoint(); - void AssignWaypoints(int32 grid, int start_wp = 0); + void AssignWaypoints(int32 grid_id, int start_wp = 0); void SetWaypointPause(); void UpdateWaypoint(int wp_index); diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 7c44472c1..47c293f12 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -561,62 +561,54 @@ void Mob::StopNavigation() { mMovementManager->StopNavigation(this); } -void NPC::AssignWaypoints(int32 grid, int start_wp) +void NPC::AssignWaypoints(int32 grid_id, int start_wp) { - if (grid == 0) + if (grid_id == 0) return; // grid ID 0 not supported - if (grid < 0) { + if (grid_id < 0) { // Allow setting negative grid values for pausing pathing - this->CastToNPC()->SetGrid(grid); + this->CastToNPC()->SetGrid(grid_id); return; } Waypoints.clear(); roamer = false; - // Retrieve the wander and pause types for this grid - std::string query = StringFormat("SELECT `type`, `type2` FROM `grid` WHERE `id` = %i AND `zoneid` = %i", grid, - zone->GetZoneID()); - auto results = content_db.QueryDatabase(query); - if (!results.Success()) { + auto grid_entry = GridRepository::GetGrid(zone->grids, grid_id); + if (grid_entry.id == 0) { return; } - if (results.RowCount() == 0) - return; + wandertype = grid_entry.type; + pausetype = grid_entry.type2; - auto row = results.begin(); - - wandertype = atoi(row[0]); - pausetype = atoi(row[1]); - - SetGrid(grid); // Assign grid number - - // Retrieve all waypoints for this grid - query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading`, `centerpoint` " - "FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i " - "ORDER BY `number`", grid, zone->GetZoneID()); - results = content_db.QueryDatabase(query); - if (!results.Success()) { - return; - } + SetGrid(grid_id); // Assign grid number roamer = true; max_wp = 0; // Initialize it; will increment it for each waypoint successfully added to the list - for (auto row = results.begin(); row != results.end(); ++row, ++max_wp) - { - wplist newwp; - newwp.index = max_wp; - newwp.x = atof(row[0]); - newwp.y = atof(row[1]); - newwp.z = atof(row[2]); + for (auto &entry : zone->grid_entries) { + if (entry.gridid == grid_id) { + wplist new_waypoint{}; + new_waypoint.index = max_wp; + new_waypoint.x = entry.x; + new_waypoint.y = entry.y; + new_waypoint.z = entry.z; + new_waypoint.pause = entry.pause; + new_waypoint.heading = entry.heading; + new_waypoint.centerpoint = entry.centerpoint; - newwp.pause = atoi(row[3]); - newwp.heading = atof(row[4]); - newwp.centerpoint = atobool(row[5]); - Waypoints.push_back(newwp); + LogPathing( + "Loading Grid [{}] number [{}] name [{}]", + grid_id, + entry.number, + GetCleanName() + ); + + Waypoints.push_back(new_waypoint); + max_wp++; + } } cur_wp = start_wp; @@ -628,8 +620,9 @@ void NPC::AssignWaypoints(int32 grid, int start_wp) patrol = cur_wp; } - if (wandertype == GridRandom10 || wandertype == GridRandom || wandertype == GridRand5LoS) + if (wandertype == GridRandom10 || wandertype == GridRandom || wandertype == GridRand5LoS) { CalculateNewWaypoint(); + } } @@ -737,7 +730,7 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) { if (IsClient() && !fix_client_z) { return; } - + if (flymode == GravityBehavior::Flying) { return; } diff --git a/zone/zone.cpp b/zone/zone.cpp index 2cdfc99d6..1bbdd411e 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1023,6 +1023,7 @@ bool Zone::Init(bool iStaticZone) { LogInfo("Init Finished: ZoneID = [{}], Time Offset = [{}]", zoneid, zone->zone_time.getEQTimeZone()); + LoadGrids(); LoadTickItems(); //MODDING HOOK FOR ZONE INIT @@ -1610,6 +1611,8 @@ void Zone::Repop(uint32 delay) if (!content_db.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay)) LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed"); + LoadGrids(); + initgrids_timer.Start(); entity_list.UpdateAllTraps(true, true); @@ -2481,3 +2484,9 @@ void Zone::SetQuestHotReloadQueued(bool in_quest_hot_reload_queued) { quest_hot_reload_queued = in_quest_hot_reload_queued; } + +void Zone::LoadGrids() +{ + grids = GridRepository::GetZoneGrids(GetZoneID()); + grid_entries = GridEntriesRepository::GetZoneGridEntries(GetZoneID()); +} diff --git a/zone/zone.h b/zone/zone.h index 1243e18c2..9dfe2c36e 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -24,6 +24,9 @@ #include "../common/types.h" #include "../common/random.h" #include "../common/string_util.h" +#include "zonedb.h" +#include "../common/repositories/grid_repository.h" +#include "../common/repositories/grid_entries_repository.h" #include "qglobals.h" #include "spawn2.h" #include "spawngroup.h" @@ -202,6 +205,9 @@ public: std::unordered_map> aa_abilities; std::unordered_map> aa_ranks; + std::vector grids; + std::vector grid_entries; + time_t weather_timer; Timer spawn2_timer; Timer hot_reload_timer; @@ -239,6 +245,7 @@ public: void LoadLDoNTrapEntries(); void LoadLDoNTraps(); void LoadLevelEXPMods(); + void LoadGrids(); void LoadMercSpells(); void LoadMercTemplates(); void LoadNewMerchantData(uint32 merchantid);