mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11:29 +00:00
* Plumbing * Batch processing in world * Cleanup * Cleanup * Update player_event_logs.cpp * Add player zoning event * Use generics * Comments * Add events * Add more events * AA_GAIN, AA_PURCHASE, FORAGE_SUCCESS, FORAGE_FAILURE * FISH_SUCCESS, FISH_FAILURE, ITEM_DESTROY * Add charges to ITEM_DESTROY * WENT_ONLINE, WENT_OFFLINE * LEVEL_GAIN, LEVEL_LOSS * LOOT_ITEM * MERCHANT_PURCHASE * MERCHANT_SELL * SKILL_UP * Add events * Add more events * TASK_ACCEPT, TASK_COMPLETE, and TASK_UPDATE * GROUNDSPAWN_PICKUP * SAY * REZ_ACCEPTED * COMBINE_FAILURE and COMBINE_SUCCESS * DROPPED_ITEM * DEATH * SPLIT_MONEY * TRADER_PURCHASE and TRADER_SELL * DISCOVER_ITEM * Convert GM_COMMAND to use new macro * Convert ZONING event to use macro * Revert some code changes * Revert "Revert some code changes" This reverts commit d53682f997e89a053a660761085913245db91e9d. * Add cereal generation support to repositories * TRADE * Formatting * Cleanup * Relocate discord_manager to discord folder * Discord sending plumbing * Rename UCS's Database class to UCSDatabase to be more specific and not collide with base Database class for repository usage * More discord sending plumbing * More discord message formatting work * More discord formatting work * Discord formatting of events * Format WENT_ONLINE, WENT_OFFLINE * Add merchant purchase event * Handle Discord MERCHANT_SELL formatter * Update player_event_discord_formatter.cpp * Tweaks * Implement retention truncation * Put mutex locking on batch queue, put processor on its own thread * Process on initial bootup * Implement optional QS processing, implement keepalive from world to QS * Reload player event settings when logs are reloaded in game * Set settings defaults * Update player_event_logs.cpp * Update player_event_logs.cpp * Set retention days on boot * Update player_event_logs.cpp * Player Handin Event Testing. Testing player handin stuff. * Cleanup. * Finish NPC Handin. * set a reference to the client inside of the trade object as well for plugins to process * Fix for windows _inline * Bump to cpp20 default, ignore excessive warnings on windows * Bump FMT to 6.1.2 for cpp20 compat and swap fmt::join for Strings::Join * Windows compile fixes * Update CMakeLists.txt * Update CMakeLists.txt * Update CMakeLists.txt * Create 2022_12_19_player_events_tables.sql * [Formatters] Work on Discord Formatters * Handin money. * Format header * [Formatters] Work on Discord Formatters * Format * Format * [Formatters] More Formatter work, need to test further. * [Formatters] More Work on Formatters. * Add missing #endif * [Formatters] Work on Formatters, fix Bot formatting in ^create help * NPC Handin Discord Formatter * Update player_event_logs.cpp * Discover Item Discord Formatter * Dropped Item Discord Formatter * Split Money Discord Formatter * Trader Discord Formatters * Cleanup. * Trade Event Discord Formatter Groundwork * SAY don't record GM commands * GM_Command don't record #help * Update player_event_logs.cpp * Fill in more event data * Post rebase fixes * Post rebase fix * Discord formatting adjustments * Add event deprecation or unimplemented tag support * Trade events * Add return money and sanity checks. * Update schema * Update ucs.cpp * Update client.cpp * Update 2022_12_19_player_events_tables.sql * Implement archive single line * Replace hackers table and functions with PossibleHack player event * Replace very old eventlog table since the same events are covered by player event logs * Update bot_command.cpp * Record NPC kill events ALL / Named / Raid * Add BatchEventProcessIntervalSeconds rule * Naming * Update CMakeLists.txt * Update database_schema.h * Remove logging function and methods * DB version * Cleanup SendPlayerHandinEvent --------- Co-authored-by: Kinglykrab <kinglykrab@gmail.com> Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
177 lines
5.4 KiB
C++
177 lines
5.4 KiB
C++
#include "dynamic_zone_manager.h"
|
|
#include "dynamic_zone.h"
|
|
#include "worlddb.h"
|
|
#include "zonelist.h"
|
|
#include "zoneserver.h"
|
|
#include "../common/rulesys.h"
|
|
#include "../common/repositories/expeditions_repository.h"
|
|
#include "../common/repositories/expedition_lockouts_repository.h"
|
|
|
|
extern ZSList zoneserver_list;
|
|
|
|
DynamicZoneManager dynamic_zone_manager;
|
|
|
|
DynamicZoneManager::DynamicZoneManager() :
|
|
m_process_throttle_timer{ static_cast<uint32_t>(RuleI(DynamicZone, WorldProcessRate)) }
|
|
{
|
|
}
|
|
|
|
void DynamicZoneManager::PurgeExpiredDynamicZones()
|
|
{
|
|
// purge when no members, instance is expired, or instance doesn't exist.
|
|
// this prevents characters remaining members of dzs that expired while
|
|
// server was offline but delayed instance purging hasn't cleaned yet
|
|
auto dz_ids = DynamicZonesRepository::GetStaleIDs(database);
|
|
|
|
if (!dz_ids.empty())
|
|
{
|
|
LogDynamicZones("Purging [{}] dynamic zone(s)", dz_ids.size());
|
|
|
|
DynamicZoneMembersRepository::DeleteWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", Strings::Join(dz_ids, ",")));
|
|
DynamicZonesRepository::DeleteWhere(database,
|
|
fmt::format("id IN ({})", Strings::Join(dz_ids, ",")));
|
|
}
|
|
}
|
|
|
|
DynamicZone* DynamicZoneManager::CreateNew(
|
|
DynamicZone& dz_request, const std::vector<DynamicZoneMember>& members)
|
|
{
|
|
// this creates a new dz instance and saves it to both db and cache
|
|
uint32_t dz_id = dz_request.Create();
|
|
if (dz_id == 0)
|
|
{
|
|
LogDynamicZones("Failed to create dynamic zone for zone [{}]", dz_request.GetZoneID());
|
|
return nullptr;
|
|
}
|
|
|
|
auto dz = std::make_unique<DynamicZone>(dz_request);
|
|
if (!members.empty())
|
|
{
|
|
dz->SaveMembers(members);
|
|
dz->CacheMemberStatuses();
|
|
}
|
|
|
|
LogDynamicZones("Created new dz [{}] for zone [{}]", dz_id, dz_request.GetZoneID());
|
|
|
|
auto pack = dz->CreateServerDzCreatePacket(0, 0);
|
|
zoneserver_list.SendPacket(pack.get());
|
|
|
|
auto inserted = dynamic_zone_cache.emplace(dz_id, std::move(dz));
|
|
return inserted.first->second.get();
|
|
}
|
|
|
|
void DynamicZoneManager::CacheNewDynamicZone(ServerPacket* pack)
|
|
{
|
|
auto buf = reinterpret_cast<ServerDzCreateSerialized_Struct*>(pack->pBuffer);
|
|
|
|
auto new_dz = std::make_unique<DynamicZone>();
|
|
new_dz->LoadSerializedDzPacket(buf->cereal_data, buf->cereal_size);
|
|
new_dz->CacheMemberStatuses();
|
|
|
|
// reserialize with member statuses cached before forwarding (restore origin zone)
|
|
auto repack = new_dz->CreateServerDzCreatePacket(buf->origin_zone_id, buf->origin_instance_id);
|
|
|
|
uint32_t dz_id = new_dz->GetID();
|
|
dynamic_zone_cache.emplace(dz_id, std::move(new_dz));
|
|
LogDynamicZones("Cached new dynamic zone [{}]", dz_id);
|
|
|
|
zoneserver_list.SendPacket(repack.get());
|
|
}
|
|
|
|
void DynamicZoneManager::CacheAllFromDatabase()
|
|
{
|
|
BenchTimer bench;
|
|
|
|
auto dynamic_zones = DynamicZonesRepository::AllWithInstanceNotExpired(database);
|
|
auto dynamic_zone_members = DynamicZoneMembersRepository::GetAllWithNames(database);
|
|
|
|
dynamic_zone_cache.clear();
|
|
dynamic_zone_cache.reserve(dynamic_zones.size());
|
|
|
|
for (auto& entry : dynamic_zones)
|
|
{
|
|
uint32_t dz_id = entry.id;
|
|
auto dz = std::make_unique<DynamicZone>(std::move(entry));
|
|
|
|
for (auto& member : dynamic_zone_members)
|
|
{
|
|
if (member.dynamic_zone_id == dz_id)
|
|
{
|
|
dz->AddMemberFromRepositoryResult(std::move(member));
|
|
}
|
|
}
|
|
|
|
// note leader status won't be updated here until leader is set by owning system (expeditions)
|
|
dz->CacheMemberStatuses();
|
|
|
|
dynamic_zone_cache.emplace(dz_id, std::move(dz));
|
|
}
|
|
|
|
LogDynamicZones("Caching [{}] dynamic zone(s) took [{}s]", dynamic_zone_cache.size(), bench.elapsed());
|
|
}
|
|
|
|
void DynamicZoneManager::Process()
|
|
{
|
|
if (!m_process_throttle_timer.Check())
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::vector<uint32_t> dynamic_zone_ids;
|
|
|
|
for (const auto& dz_iter : dynamic_zone_cache)
|
|
{
|
|
DynamicZone* dz = dz_iter.second.get();
|
|
|
|
// dynamic zone is not deleted until its zone has no clients to prevent exploits
|
|
// clients should be removed by zone-based kick timers if expired but not empty
|
|
DynamicZoneStatus status = dz->Process();
|
|
if (status == DynamicZoneStatus::ExpiredEmpty)
|
|
{
|
|
LogDynamicZones("[{}] expired with [{}] members, notifying zones and deleting", dz->GetID(), dz->GetMemberCount());
|
|
dynamic_zone_ids.emplace_back(dz->GetID());
|
|
dz->SendZonesDynamicZoneDeleted(); // delete dz from zone caches
|
|
}
|
|
}
|
|
|
|
if (!dynamic_zone_ids.empty())
|
|
{
|
|
for (const auto& dz_id : dynamic_zone_ids)
|
|
{
|
|
dynamic_zone_cache.erase(dz_id);
|
|
}
|
|
|
|
// need to look up expedition ids until lockouts are moved to dynamic zones
|
|
std::vector<uint32_t> expedition_ids;
|
|
auto expeditions = ExpeditionsRepository::GetWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", Strings::Join(dynamic_zone_ids, ",")));
|
|
|
|
if (!expeditions.empty())
|
|
{
|
|
for (const auto& expedition : expeditions)
|
|
{
|
|
expedition_ids.emplace_back(expedition.id);
|
|
}
|
|
ExpeditionLockoutsRepository::DeleteWhere(database,
|
|
fmt::format("expedition_id IN ({})", Strings::Join(expedition_ids, ",")));
|
|
}
|
|
|
|
ExpeditionsRepository::DeleteWhere(database,
|
|
fmt::format("dynamic_zone_id IN ({})", Strings::Join(dynamic_zone_ids, ",")));
|
|
DynamicZoneMembersRepository::RemoveAllMembers(database, dynamic_zone_ids);
|
|
DynamicZonesRepository::DeleteWhere(database,
|
|
fmt::format("id IN ({})", Strings::Join(dynamic_zone_ids, ",")));
|
|
}
|
|
}
|
|
|
|
void DynamicZoneManager::LoadTemplates()
|
|
{
|
|
m_dz_templates.clear();
|
|
auto dz_templates = DynamicZoneTemplatesRepository::All(content_db);
|
|
for (const auto& dz_template : dz_templates)
|
|
{
|
|
m_dz_templates[dz_template.id] = dz_template;
|
|
}
|
|
}
|