mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 08:21:28 +00:00
[Zoning] Improve zone routing (#4428)
* [Zoning] Improvements to zone routing * Update world_content_service.h * Update world_content_service.h
This commit is contained in:
parent
d5cbec714e
commit
70a96ea098
@ -6,6 +6,7 @@
|
|||||||
#include "../rulesys.h"
|
#include "../rulesys.h"
|
||||||
#include "../eqemu_logsys.h"
|
#include "../eqemu_logsys.h"
|
||||||
#include "../repositories/instance_list_repository.h"
|
#include "../repositories/instance_list_repository.h"
|
||||||
|
#include "../zone_store.h"
|
||||||
|
|
||||||
|
|
||||||
WorldContentService::WorldContentService()
|
WorldContentService::WorldContentService()
|
||||||
@ -183,8 +184,8 @@ void WorldContentService::ReloadContentFlags()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetContentFlags(set_content_flags);
|
SetContentFlags(set_content_flags);
|
||||||
LoadZones();
|
|
||||||
LoadStaticGlobalZoneInstances();
|
LoadStaticGlobalZoneInstances();
|
||||||
|
zone_store.LoadZones(*m_content_database);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database *WorldContentService::GetDatabase() const
|
Database *WorldContentService::GetDatabase() const
|
||||||
@ -236,18 +237,6 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
|
|||||||
ReloadContentFlags();
|
ReloadContentFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
|
|
||||||
//
|
|
||||||
// example # 1
|
|
||||||
// lavastorm (pre-don) version 0 (classic)
|
|
||||||
// lavastorm (don) version 1
|
|
||||||
// we want to route players to the correct version of lavastorm based on the current server side expansion
|
|
||||||
// in order to do that the simplest and cleanest way we intercept the zoning process and route players to an "instance" of the zone
|
|
||||||
// the reason why we're doing this is because all of the zoning logic already is handled by two keys "zone_id" and "instance_id"
|
|
||||||
// we can leverage static, never expires instances to handle this but to the client they don't see it any other way than a public normal zone
|
|
||||||
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
|
|
||||||
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
|
||||||
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
|
||||||
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
||||||
{
|
{
|
||||||
auto r = FindZone(zc->zoneID, zc->instanceID);
|
auto r = FindZone(zc->zoneID, zc->instanceID);
|
||||||
@ -261,93 +250,72 @@ void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
|||||||
// LoadStaticGlobalZoneInstances loads all static global zone instances
|
// LoadStaticGlobalZoneInstances loads all static global zone instances
|
||||||
// these are zones that are never set to expire and are global
|
// these are zones that are never set to expire and are global
|
||||||
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
|
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
|
||||||
WorldContentService * WorldContentService::LoadStaticGlobalZoneInstances()
|
WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
|
||||||
{
|
{
|
||||||
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
|
m_zone_static_instances = InstanceListRepository::GetWhere(
|
||||||
|
*GetDatabase(),
|
||||||
|
fmt::format("never_expires = 1 AND is_global = 1")
|
||||||
|
);
|
||||||
|
|
||||||
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
|
LogInfo("Loaded [{}] zone_instances", m_zone_static_instances.size());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadZones sets the zones for the world content service
|
// FindZone handles content and context aware zone routing (middleware)
|
||||||
// this is used for zone routing middleware
|
//
|
||||||
// we pull the zone list from the zone repository and feed from the zone store for now
|
// this is a middleware function that is meant to be used in the zone change process
|
||||||
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
|
// this hooks all core zone changes within the server and routes the player to the correct zone
|
||||||
WorldContentService * WorldContentService::LoadZones()
|
// returning a zone_id of non-zero means the middleware will route the player
|
||||||
{
|
// returning a zone_id of 0 means the middleware will not route the player
|
||||||
m_zones = ZoneRepository::All(*GetContentDatabase());
|
// this is useful for handling multiple versions of the same zone
|
||||||
|
//
|
||||||
LogInfo("Loaded [{}] zones", m_zones.size());
|
// implementation >
|
||||||
|
// the zoning and process spawning logic already is handled by two keys "zone_id" and "instance_id"
|
||||||
return this;
|
// we leverage static, never expires instances to handle this and client still sees it as a normal zone
|
||||||
}
|
//
|
||||||
|
// content awareness >
|
||||||
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
|
// simply use the zone_id, server content settings and the middleware will handle the rest
|
||||||
// era contextual routing, multiple version of zones, etc
|
// you don't have to think about instances in any data tables (use instance_id 0)
|
||||||
|
// you don't have to keep track of instance ids in scripts (use instance_id 0)
|
||||||
|
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
||||||
|
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
||||||
|
//
|
||||||
|
// example >
|
||||||
|
// we want to route players to the correct version of lavastorm based on the current server side expansion (DoesZonePassContentFiltering)
|
||||||
|
// lavastorm (pre-don) version 0 (classic)
|
||||||
|
// zone table entry for version = 0, min_expansion = 0, max_expansion = 8
|
||||||
|
// instance_list table entry for lavastorm has version = 0, is_global = 1, never_expires = 1
|
||||||
|
// lavastorm (don) version 1
|
||||||
|
// zone table entry for version = 1, min_expansion = 9, max_expansion = 99
|
||||||
|
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
|
||||||
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
|
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
|
||||||
{
|
{
|
||||||
// if there's an active dynamic instance, we don't need to route
|
for (const auto &z: zone_store.GetZones()) {
|
||||||
if (instance_id > 0) {
|
for (auto &i: m_zone_static_instances) {
|
||||||
auto inst = InstanceListRepository::FindOne(*GetDatabase(), instance_id);
|
if (
|
||||||
if (inst.id != 0 && !inst.is_global && !inst.never_expires) {
|
z.zoneidnumber == zone_id &&
|
||||||
return WorldContentService::FindZoneResult{
|
DoesZonePassContentFiltering(z) &&
|
||||||
.zone_id = 0,
|
i.zone == zone_id &&
|
||||||
};
|
i.version == z.version) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &z: m_zones) {
|
if (instance_id > 0 && i.id != instance_id) {
|
||||||
if (z.zoneidnumber == zone_id) {
|
continue;
|
||||||
auto f = ContentFlags{
|
|
||||||
.min_expansion = z.min_expansion,
|
|
||||||
.max_expansion = z.max_expansion,
|
|
||||||
.content_flags = z.content_flags,
|
|
||||||
.content_flags_disabled = z.content_flags_disabled
|
|
||||||
};
|
|
||||||
|
|
||||||
if (DoesPassContentFiltering(f)) {
|
|
||||||
LogInfo(
|
|
||||||
"Attempting to route player to zone [{}] ({}) version [{}] long_name [{}]",
|
|
||||||
z.short_name,
|
|
||||||
z.zoneidnumber,
|
|
||||||
z.version,
|
|
||||||
z.long_name
|
|
||||||
);
|
|
||||||
|
|
||||||
// first pass, explicit match on public static global zone instances
|
|
||||||
for (auto &i: m_zone_instances) {
|
|
||||||
if (i.zone == zone_id && i.version == z.version) {
|
|
||||||
LogInfo(
|
|
||||||
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
|
||||||
i.id,
|
|
||||||
z.short_name,
|
|
||||||
z.zoneidnumber,
|
|
||||||
z.version,
|
|
||||||
z.long_name,
|
|
||||||
i.notes
|
|
||||||
);
|
|
||||||
|
|
||||||
return WorldContentService::FindZoneResult{
|
|
||||||
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
|
||||||
.instance = i,
|
|
||||||
.zone = z
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
"Routed player to public static instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
||||||
|
i.id,
|
||||||
z.short_name,
|
z.short_name,
|
||||||
z.zoneidnumber,
|
z.zoneidnumber,
|
||||||
z.version,
|
z.version,
|
||||||
z.long_name,
|
z.long_name,
|
||||||
z.note
|
i.notes
|
||||||
);
|
);
|
||||||
|
|
||||||
return WorldContentService::FindZoneResult{
|
return WorldContentService::FindZoneResult{
|
||||||
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
||||||
.instance = InstanceListRepository::NewEntity(),
|
.instance = i,
|
||||||
.zone = z
|
.zone = z
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -359,7 +327,7 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
|
|||||||
|
|
||||||
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
||||||
{
|
{
|
||||||
for (auto &i: m_zone_instances) {
|
for (auto &i: m_zone_static_instances) {
|
||||||
if (i.id == instance_id) {
|
if (i.id == instance_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -367,3 +335,15 @@ bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldContentService::DoesZonePassContentFiltering(const ZoneRepository::Zone &z)
|
||||||
|
{
|
||||||
|
auto f = ContentFlags{
|
||||||
|
.min_expansion = z.min_expansion,
|
||||||
|
.max_expansion = z.max_expansion,
|
||||||
|
.content_flags = z.content_flags,
|
||||||
|
.content_flags_disabled = z.content_flags_disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
return DoesPassContentFiltering(f);
|
||||||
|
}
|
||||||
|
|||||||
@ -160,6 +160,7 @@ public:
|
|||||||
WorldContentService * SetExpansionContext();
|
WorldContentService * SetExpansionContext();
|
||||||
|
|
||||||
bool DoesPassContentFiltering(const ContentFlags& f);
|
bool DoesPassContentFiltering(const ContentFlags& f);
|
||||||
|
bool DoesZonePassContentFiltering(const ZoneRepository::Zone& z);
|
||||||
|
|
||||||
WorldContentService * SetDatabase(Database *database);
|
WorldContentService * SetDatabase(Database *database);
|
||||||
Database *GetDatabase() const;
|
Database *GetDatabase() const;
|
||||||
@ -189,10 +190,8 @@ private:
|
|||||||
Database *m_content_database;
|
Database *m_content_database;
|
||||||
|
|
||||||
// holds a record of the zone table from the database
|
// holds a record of the zone table from the database
|
||||||
std::vector<ZoneRepository::Zone> m_zones = {};
|
|
||||||
WorldContentService *LoadStaticGlobalZoneInstances();
|
WorldContentService *LoadStaticGlobalZoneInstances();
|
||||||
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
|
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
|
||||||
WorldContentService * LoadZones();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern WorldContentService content_service;
|
extern WorldContentService content_service;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user