Keeps spawns from doing individual loads and prefer bulk loading [skip ci]

This commit is contained in:
Akkadius 2020-03-30 23:25:32 -05:00
parent 0c3dd7dc93
commit 019735c654
8 changed files with 210 additions and 63 deletions

View File

@ -199,6 +199,7 @@ SET(common_headers
repositories/character_recipe_list_repository.h repositories/character_recipe_list_repository.h
repositories/grid_repository.h repositories/grid_repository.h
repositories/grid_entries_repository.h repositories/grid_entries_repository.h
repositories/spawngroup_repository.h
repositories/tradeskill_recipe_repository.h repositories/tradeskill_recipe_repository.h
rdtsc.h rdtsc.h
rulesys.h rulesys.h

View File

@ -0,0 +1,164 @@
/**
* 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_SPAWNGROUP_REPOSITORY_H
#define EQEMU_SPAWNGROUP_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
class SpawnGroupRepository {
public:
struct SpawnGroup {
int id;
std::string name;
int8 spawn_limit;
int dist;
float max_x;
float min_x;
float max_y;
float min_y;
int delay;
int mindelay;
int despawn;
int despawn_timer;
int wp_spawns;
};
static std::vector<std::string> Columns()
{
return {
"id",
"name",
"spawn_limit",
"dist",
"max_x",
"min_x",
"max_y",
"min_y",
"delay",
"mindelay",
"despawn",
"despawn_timer",
"wp_spawns",
};
}
static std::string ColumnsRaw()
{
return std::string(implode(", ", Columns()));
}
static std::string TableName()
{
return std::string("spawngroup");
}
static std::string BaseSelect()
{
return std::string(
fmt::format(
"SELECT {} FROM {}",
ColumnsRaw(),
TableName()
)
);
}
static SpawnGroup New()
{
SpawnGroup entry;
entry.id = 0;
entry.name = "";
entry.spawn_limit = 0;
entry.dist = 0;
entry.max_x = 0;
entry.min_x = 0;
entry.max_y = 0;
entry.min_y = 0;
entry.delay = 0;
entry.mindelay = 0;
entry.despawn = 0;
entry.despawn_timer = 0;
entry.wp_spawns = 0;
return entry;
}
static std::vector<SpawnGroup> GetZoneSpawnGroups(
const std::string &zone_short_name,
int zone_version
)
{
std::vector<SpawnGroup> spawn_groups;
auto results = content_db.QueryDatabase(
fmt::format(
SQL (
{} INNER JOIN spawn2 ON spawn2.spawngroupID = spawngroup.id
WHERE spawn2.zone = '{}' and spawn2.version = {}
),
BaseSelect(),
zone_short_name,
zone_version
)
);
for (auto row = results.begin(); row != results.end(); ++row) {
SpawnGroup entry{};
entry.id = atoi(row[0]);
entry.name = row[1];
entry.spawn_limit = atoi(row[2]);
entry.dist = atof(row[3]);
entry.max_x = atof(row[4]);
entry.min_x = atof(row[5]);
entry.max_y = atof(row[6]);
entry.min_y = atof(row[7]);
entry.delay = atoi(row[8]);
entry.mindelay = atoi(row[9]);
entry.despawn = atoi(row[10]);
entry.despawn_timer = atoi(row[11]);
entry.wp_spawns = atoi(row[12]);
spawn_groups.push_back(entry);
}
return spawn_groups;
}
static SpawnGroup GetGrid(
const std::vector<SpawnGroup> &spawn_groups,
int spawn_group_id
)
{
for (auto &row : spawn_groups) {
if (row.id == spawn_group_id) {
return row;
}
}
return New();
}
};
#endif //EQEMU_SPAWNGROUP_REPOSITORY_H

View File

@ -345,7 +345,6 @@ int command_init(void)
command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) || command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) ||
command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) || command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) ||
command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) ||
command_add("repopclose", "[distance in units] Repops only NPC's nearby for fast development purposes", 100, command_repopclose) ||
command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) ||
command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) ||
command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) ||
@ -5320,33 +5319,6 @@ void command_repop(Client *c, const Seperator *sep)
zone->spawn2_timer.Trigger(); zone->spawn2_timer.Trigger();
} }
void command_repopclose(Client *c, const Seperator *sep)
{
int repop_distance = 500;
if (sep->arg[1] && strcasecmp(sep->arg[1], "force") == 0) {
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
while (iterator.MoreElements()) {
std::string query = StringFormat(
"DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu",
(unsigned long)iterator.GetData()->GetID(),
(unsigned long)zone->GetInstanceID()
);
auto results = database.QueryDatabase(query);
iterator.Advance();
}
c->Message(Chat::White, "Zone depop: Force resetting spawn timers.");
}
if (sep->IsNumber(1)) {
repop_distance = atoi(sep->arg[1]);
}
c->Message(Chat::White, "Zone depoped. Repopping NPC's within %i distance units", repop_distance);
zone->RepopClose(c->GetPosition(), repop_distance);
}
void command_spawnstatus(Client *c, const Seperator *sep) void command_spawnstatus(Client *c, const Seperator *sep)
{ {
if((sep->arg[1][0] == 'e') | (sep->arg[1][0] == 'E')) if((sep->arg[1][0] == 'e') | (sep->arg[1][0] == 'E'))

View File

@ -246,7 +246,6 @@ void command_reloadworld(Client *c, const Seperator *sep);
void command_reloadworldrules(Client *c, const Seperator *sep); void command_reloadworldrules(Client *c, const Seperator *sep);
void command_reloadzps(Client *c, const Seperator *sep); void command_reloadzps(Client *c, const Seperator *sep);
void command_repop(Client *c, const Seperator *sep); void command_repop(Client *c, const Seperator *sep);
void command_repopclose(Client *c, const Seperator *sep);
void command_resetaa(Client* c,const Seperator *sep); void command_resetaa(Client* c,const Seperator *sep);
void command_resetaa_timer(Client *c, const Seperator *sep); void command_resetaa_timer(Client *c, const Seperator *sep);
void command_revoke(Client *c, const Seperator *sep); void command_revoke(Client *c, const Seperator *sep);

View File

@ -165,7 +165,10 @@ bool Spawn2::Process() {
return (true); return (true);
} }
if (spawn_group == nullptr) { /**
* Wait for init grids timer because we bulk load this data before trying to fetch it individually
*/
if (spawn_group == nullptr && zone->GetInitgridsTimer().Check()) {
content_db.LoadSpawnGroupsByID(spawngroup_id_, &zone->spawn_group_list); content_db.LoadSpawnGroupsByID(spawngroup_id_, &zone->spawn_group_list);
spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
} }
@ -916,7 +919,7 @@ void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 inst
"(id, value, zone, instance_id) " "(id, value, zone, instance_id) "
"VALUES( %u, %u, '%s', %u)", "VALUES( %u, %u, '%s', %u)",
cond_id, value, zone_name, instance_id); cond_id, value, zone_name, instance_id);
content_db.QueryDatabase(query); database.QueryDatabase(query);
} }
bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) { bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) {
@ -1376,7 +1379,7 @@ int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instanc
"WHERE zone = '%s' AND instance_id = %u AND id = %d", "WHERE zone = '%s' AND instance_id = %u AND id = %d",
zone_short, instance_id, condition_id zone_short, instance_id, condition_id
); );
auto results = content_db.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
LogSpawns("Unable to query remote condition [{}] from zone [{}] in Get request", condition_id, zone_short); LogSpawns("Unable to query remote condition [{}] from zone [{}] in Get request", condition_id, zone_short);
return 0; //dunno a better thing to do... return 0; //dunno a better thing to do...

View File

@ -325,6 +325,14 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn
} }
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
LogSpawnsDetail(
"[LoadSpawnGroupsByID] Loading spawn_group spawn_group_id [{}] name [{}] spawn_limit [{}] dist [{}]",
row[0],
row[1],
row[2],
row[3]
);
auto new_spawn_group = new SpawnGroup( auto new_spawn_group = new SpawnGroup(
atoi(row[0]), atoi(row[0]),
row[1], row[1],
@ -375,6 +383,15 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn
(row[4] ? atoi(row[4]) : 0) (row[4] ? atoi(row[4]) : 0)
); );
LogSpawnsDetail(
"[LoadSpawnGroupsByID] Loading spawn_entry spawn_group_id [{}] npc_id [{}] chance [{}] condition_value_filter [{}] spawn_limit [{}]",
row[0],
row[1],
row[2],
row[3],
row[4]
);
SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(atoi(row[0])); SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(atoi(row[0]));
if (!spawn_group) { if (!spawn_group) {
safe_delete(new_spawn_entry); safe_delete(new_spawn_entry);

View File

@ -1272,8 +1272,6 @@ bool Zone::Process() {
EQEmu::InventoryProfile::CleanDirty(); EQEmu::InventoryProfile::CleanDirty();
LogSpawns("Running Zone::Process -> Spawn2::Process");
iterator.Reset(); iterator.Reset();
while (iterator.MoreElements()) { while (iterator.MoreElements()) {
if (iterator.GetData()->Process()) { if (iterator.GetData()->Process()) {
@ -1598,29 +1596,6 @@ void Zone::ClearNPCTypeCache(int id) {
} }
} }
void Zone::RepopClose(const glm::vec4& client_position, uint32 repop_distance)
{
if (!Depop())
return;
LinkedListIterator<Spawn2*> iterator(spawn2_list);
iterator.Reset();
while (iterator.MoreElements()) {
iterator.RemoveCurrent();
}
quest_manager.ClearAllTimers();
if (!content_db.PopulateZoneSpawnListClose(zoneid, spawn2_list, GetInstanceVersion(), client_position, repop_distance))
LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed");
initgrids_timer.Start();
mod_repop();
}
void Zone::Repop(uint32 delay) void Zone::Repop(uint32 delay)
{ {
if (!Depop()) { if (!Depop()) {
@ -1640,8 +1615,19 @@ void Zone::Repop(uint32 delay)
quest_manager.ClearAllTimers(); quest_manager.ClearAllTimers();
if (!content_db.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay)) LogInfo("Loading spawn groups");
if (!content_db.LoadSpawnGroups(short_name, GetInstanceVersion(), &spawn_group_list)) {
LogError("Loading spawn groups failed");
}
LogInfo("Loading spawn conditions");
if (!spawn_conditions.LoadSpawnConditions(short_name, instanceid)) {
LogError("Loading spawn conditions failed, continuing without them");
}
if (!content_db.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay)) {
LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed"); LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed");
}
LoadGrids(); LoadGrids();
@ -2522,3 +2508,8 @@ void Zone::LoadGrids()
zone_grids = GridRepository::GetZoneGrids(GetZoneID()); zone_grids = GridRepository::GetZoneGrids(GetZoneID());
zone_grid_entries = GridEntriesRepository::GetZoneGridEntries(GetZoneID()); zone_grid_entries = GridEntriesRepository::GetZoneGridEntries(GetZoneID());
} }
Timer Zone::GetInitgridsTimer()
{
return initgrids_timer;
}

View File

@ -259,7 +259,6 @@ public:
void RemoveAuth(const char *iCharName, const char *iLSKey); void RemoveAuth(const char *iCharName, const char *iLSKey);
void RemoveAuth(uint32 lsid); void RemoveAuth(uint32 lsid);
void Repop(uint32 delay = 0); void Repop(uint32 delay = 0);
void RepopClose(const glm::vec4 &client_position, uint32 repop_distance);
void RequestUCSServerStatus(); void RequestUCSServerStatus();
void ResetAuth(); void ResetAuth();
void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute); void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute);
@ -285,6 +284,8 @@ public:
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f);
ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f);
Timer GetInitgridsTimer();
/** /**
* GMSay Callback for LogSys * GMSay Callback for LogSys
* *
@ -332,6 +333,7 @@ public:
double GetMaxMovementUpdateRange() const { return max_movement_update_range; } double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
/** /**
* Modding hooks * Modding hooks
*/ */
@ -352,8 +354,6 @@ private:
bool staticzone; bool staticzone;
bool zone_has_current_time; bool zone_has_current_time;
bool quest_hot_reload_queued; bool quest_hot_reload_queued;
private:
double max_movement_update_range; double max_movement_update_range;
char *long_name; char *long_name;
char *map_name; char *map_name;
@ -384,7 +384,7 @@ private:
Timer autoshutdown_timer; Timer autoshutdown_timer;
Timer clientauth_timer; Timer clientauth_timer;
Timer hotzone_timer; Timer hotzone_timer;
Timer initgrids_timer; //delayed loading of initial grids. Timer initgrids_timer;
Timer qglobal_purge_timer; Timer qglobal_purge_timer;
ZoneSpellsBlocked *blocked_spells; ZoneSpellsBlocked *blocked_spells;