fix: the master server only starts instances of zones in the ZoneTable

A transfer or private zone request started a world server for whatever
map ID it named, and for as many instances as were asked for. A new
instance now needs a row in the ZoneTable for its zone, and no more
than max_instances (masterconfig.ini, 256 by default, 0 for no limit)
run at once. The character select has no row and is always started.

A request that gets no instance is logged and dropped. Before, the
handlers went on to use the missing instance.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 15:37:09 -06:00
parent 5f20e0b3d2
commit e164f9aaed
8 changed files with 115 additions and 0 deletions

View File

@@ -11,6 +11,7 @@
#include "CDClientManager.h"
#include "CDZoneTableTable.h"
#include "Database.h"
#include "InstanceLimits.h"
#include "MasterPackets.h"
#include "BitStreamUtils.h"
#include "ServiceType.h"
@@ -46,6 +47,23 @@ InstanceManager::InstanceManager(const std::string& externalIP) : mExternalIP{ e
m_LastPort =
GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("world_port_start")).value_or(m_LastPort);
m_LastInstanceID = LWOINSTANCEID_INVALID;
m_MaxInstances =
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_instances")).value_or(InstanceLimits::DefaultMaxInstances);
}
bool InstanceManager::CanCreateInstance(const LWOMAPID mapID, const LWOCLONEID cloneID) const {
const bool isInZoneTable = mapID != 0 && CDZoneTableTable::Query(mapID) != nullptr;
switch (InstanceLimits::CheckNewInstance(mapID, isInZoneTable, m_Instances.size(), m_MaxInstances)) {
case InstanceLimits::eNewInstance::UnknownZone:
LOG("Tried to create an instance of map %i/%i, which is not in the ZoneTable.", mapID, cloneID);
return false;
case InstanceLimits::eNewInstance::TooManyInstances:
LOG("Tried to create an instance of map %i/%i, but %zu instances run already and max_instances is %u.", mapID, cloneID, m_Instances.size(), m_MaxInstances);
return false;
default:
return true;
}
}
const InstancePtr& InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID) {
@@ -65,6 +83,9 @@ const InstancePtr& InstanceManager::CreateInstance(LWOMAPID mapID, LWOCLONEID cl
cloneID);
return g_Empty;
}
if (!CanCreateInstance(mapID, cloneID)) return g_Empty;
int softCap = 8;
int maxPlayers = 12;
@@ -360,6 +381,8 @@ const InstancePtr& InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLO
return g_Empty;
}
if (!CanCreateInstance(mapID, cloneID)) return g_Empty;
int maxPlayers = 999;
uint32_t port = GetFreePort();