mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-07-30 00:15:47 -04:00
Added CentralServer project
This commit is contained in:
@@ -0,0 +1,374 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// CharacterCreationTracker.cpp
|
||||
// copyright (c) 2001 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "FirstCentralServer.h"
|
||||
#include "CharacterCreationTracker.h"
|
||||
|
||||
#include "ConfigCentralServer.h"
|
||||
#include "UnicodeUtils.h"
|
||||
#include "serverNetworkMessages/CentralConnectionServerMessages.h"
|
||||
#include "serverNetworkMessages/LoginCreateCharacterAckMessage.h"
|
||||
#include "serverNetworkMessages/LoginCreateCharacterMessage.h"
|
||||
#include "serverUtility/ServerClock.h"
|
||||
#include "sharedFoundation/Clock.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedFoundation/FormattedString.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
|
||||
#include "sharedNetworkMessages/NameErrors.h"
|
||||
#include "sharedNetworkMessages/NetworkStringIds.h"
|
||||
#include "sharedUtility/StartingLocationData.h"
|
||||
#include "sharedUtility/StartingLocationManager.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
CharacterCreationTracker * CharacterCreationTracker::ms_instance = NULL;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void CharacterCreationTracker::install()
|
||||
{
|
||||
DEBUG_FATAL(ms_instance != NULL,("Called install() twice.\n"));
|
||||
ms_instance = new CharacterCreationTracker;
|
||||
ExitChain::add(CharacterCreationTracker::remove,"CharacterCreationTracker::remove");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::remove()
|
||||
{
|
||||
DEBUG_FATAL(!ms_instance,("Not installed.\n"));
|
||||
delete ms_instance;
|
||||
ms_instance = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
CharacterCreationTracker::CharacterCreationTracker() :
|
||||
m_creations()
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
CharacterCreationTracker::~CharacterCreationTracker()
|
||||
{
|
||||
for (CreationsType::iterator i = m_creations.begin(); i != m_creations.end(); ++i)
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::handleCreateNewCharacter(const ConnectionCreateCharacter &msg)
|
||||
{
|
||||
// - Check whether a creation request is already active for this account
|
||||
CreationsType::iterator creationRecord = m_creations.find(msg.getStationId());
|
||||
if (creationRecord != m_creations.end())
|
||||
{
|
||||
if (ServerClock::getInstance().getGameTimeSeconds() > (creationRecord->second->m_creationTime + ConfigCentralServer::getCharacterCreationTimeout()))
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d allowing character creation because previous one timed out", msg.getStationId()));
|
||||
DEBUG_REPORT_LOG(true,("Allowing character creation for account %li because previous one timed out.\n",msg.getStationId()));
|
||||
unlockAccount(msg.getStationId());
|
||||
creationRecord = m_creations.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d refusing character creation because one is already in progress", msg.getStationId()));
|
||||
DEBUG_REPORT_LOG(true,("Refusing character creation for account %li because one was already in progress.\n",msg.getStationId()));
|
||||
ConnectionCreateCharacterFailed f(msg.getStationId(), msg.getCharacterName(), NameErrors::nameDeclinedRetry, FormattedString<2048>().sprintf("%lu refusing character creation because one is already in progress", msg.getStationId())); //lint !e40 // undeclared identifier nameDeclinedEntry
|
||||
CentralServer::getInstance().sendToConnectionServerForAccount(msg.getStationId(), f, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// - Check whether they are creating characters too rapidly
|
||||
// Note that this locks only when creation succeeds. Failing to create a lot of characters in a row does not lock the account.
|
||||
FastCreationLockType::iterator fcl = m_fastCreationLock.find(msg.getStationId());
|
||||
if (fcl != m_fastCreationLock.end())
|
||||
{
|
||||
if (!msg.getNoRateLimit() && ((Clock::timeSeconds() - fcl->second) < (msg.getIsForCharacterTransfer() ? static_cast<uint32>(ConfigCentralServer::getCharacterCtsCreationRateLimitSeconds()) : static_cast<uint32>(ConfigCentralServer::getCharacterCreationRateLimitSeconds()))))
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d refusing character creation because not enough time has passed since the previous one", msg.getStationId()));
|
||||
DEBUG_REPORT_LOG(true,("Refusing character creation for account %li because not enough time has passed since the previous one\n",msg.getStationId()));
|
||||
ConnectionCreateCharacterFailed f(msg.getStationId(), msg.getCharacterName(), NameErrors::nameDeclinedTooFast, FormattedString<2048>().sprintf("%lu refusing character creation because not enough time has passed since the previous one", msg.getStationId()));
|
||||
CentralServer::getInstance().sendToConnectionServerForAccount(msg.getStationId(), f, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (creationRecord == m_creations.end())
|
||||
creationRecord = m_creations.insert(std::make_pair<StationId,CreationRecord*>(msg.getStationId(),new CreationRecord)).first;
|
||||
|
||||
// - determine starting location
|
||||
static std::string tutorialPlanetName("tutorial");
|
||||
std::string planetName;
|
||||
Vector coordinates(0.0f,0.0f,0.0f);
|
||||
NetworkId cellId(NetworkId::cms_invalid);
|
||||
bool useNewbieTutorial = (ConfigCentralServer::getNewbieTutorialEnabled() && msg.getUseNewbieTutorial() && ! msg.getIsForCharacterTransfer());
|
||||
if (useNewbieTutorial)
|
||||
planetName = tutorialPlanetName;
|
||||
else
|
||||
{
|
||||
if (!getStartLocation(msg.getStartingLocation(), planetName, coordinates, cellId))
|
||||
{
|
||||
// bad starting location
|
||||
LOG("TraceCharacterCreation", ("%d bad starting location (%s)", msg.getStationId(), msg.getStartingLocation().c_str()));
|
||||
ConnectionCreateCharacterFailed cccf(msg.getStationId(), msg.getCharacterName(), SharedStringIds::character_create_failed_bad_location, FormattedString<2048>().sprintf("%lu bad starting location (%s)", msg.getStationId(), msg.getStartingLocation().c_str()));
|
||||
CentralServer::getInstance().sendToConnectionServerForAccount(msg.getStationId(), cccf, true);
|
||||
unlockAccount(msg.getStationId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// - send request to game server
|
||||
creationRecord->second->m_gameCreationRequest = new CentralCreateCharacter(
|
||||
msg.getStationId(),
|
||||
msg.getCharacterName(),
|
||||
msg.getTemplateName(),
|
||||
msg.getScaleFactor(),
|
||||
planetName,
|
||||
coordinates,
|
||||
cellId,
|
||||
msg.getAppearanceData(),
|
||||
msg.getHairTemplateName(),
|
||||
msg.getHairAppearanceData(),
|
||||
msg.getProfession(),
|
||||
msg.getBiography(),
|
||||
useNewbieTutorial,
|
||||
msg.getSkillTemplate(),
|
||||
msg.getWorkingSkill(),
|
||||
msg.getJedi(),
|
||||
msg.getGameFeatures());
|
||||
uint32 gameServerId = CentralServer::getInstance().sendToRandomGameServer(*(creationRecord->second->m_gameCreationRequest));
|
||||
if (gameServerId == 0)
|
||||
{
|
||||
DEBUG_REPORT_LOG(true, ("Could not find a game server for character creation, starting a tutorial server\n"));
|
||||
LOG("TraceCharacterCreation", ("%d waiting for game server", msg.getStationId()));
|
||||
CentralServer::getInstance().startPlanetServer(CentralServer::getInstance().getHostForScene(tutorialPlanetName), tutorialPlanetName, 0);
|
||||
creationRecord->second->m_stage = CreationRecord::S_queuedForGameServer;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("TraceCharacterCreation", ("%d sending CentralCreateCharacter(%s) to game server %lu", msg.getStationId(), Unicode::wideToNarrow(msg.getCharacterName()).c_str(), gameServerId));
|
||||
creationRecord->second->m_stage = CreationRecord::S_sentToGameServer;
|
||||
creationRecord->second->m_gameServerId = gameServerId;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::unlockAccount(StationId account)
|
||||
{
|
||||
delete m_creations[account];
|
||||
IGNORE_RETURN(m_creations.erase(account));
|
||||
LOG("TraceCharacterCreation", ("%d removing character creation lock", account));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::retryGameServerCreates()
|
||||
{
|
||||
for (CreationsType::iterator i=m_creations.begin(); i!=m_creations.end(); ++i)
|
||||
{
|
||||
if (i->second->m_stage == CreationRecord::S_queuedForGameServer)
|
||||
{
|
||||
uint32 gameServerId = CentralServer::getInstance().sendToRandomGameServer(*i->second->m_gameCreationRequest);
|
||||
if (gameServerId != 0)
|
||||
{
|
||||
i->second->m_stage = CreationRecord::S_sentToGameServer;
|
||||
i->second->m_gameServerId = gameServerId;
|
||||
LOG("TraceCharacterCreation", ("%d sending CentralCreateCharacter to game server %lu", i->first,gameServerId));
|
||||
}
|
||||
else
|
||||
{
|
||||
i->second->m_gameServerId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::retryLoginServerCreates()
|
||||
{
|
||||
for (CreationsType::iterator i=m_creations.begin(); i!=m_creations.end(); ++i)
|
||||
{
|
||||
if (i->second->m_stage == CreationRecord::S_queuedForLoginServer)
|
||||
{
|
||||
uint32 loginServerId = CentralServer::getInstance().sendToArbitraryLoginServer(*i->second->m_loginCreationRequest, false);
|
||||
if (loginServerId != 0 )
|
||||
{
|
||||
i->second->m_loginServerId = loginServerId;
|
||||
i->second->m_stage = CreationRecord::S_sentToLoginServer;
|
||||
LOG("TraceCharacterCreation", ("%d sending LoginCreateCharacterMessage", i->first));
|
||||
}
|
||||
else
|
||||
{
|
||||
i->second->m_loginServerId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const bool CharacterCreationTracker::getStartLocation(const std::string & name, std::string & planetName, Vector & coordinates, NetworkId & cellId) const
|
||||
{
|
||||
const StartingLocationData * const sld = StartingLocationManager::findLocationByName (name);
|
||||
if (sld)
|
||||
{
|
||||
planetName = sld->planet;
|
||||
coordinates.x = sld->x;
|
||||
coordinates.z = sld->z;
|
||||
cellId = NetworkId (sld->cellId);
|
||||
return true;
|
||||
}
|
||||
|
||||
REPORT_LOG(true, ("The start location \"%s\" could not be found in StartingLocationManager", name.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::onGameServerDisconnect(uint32 serverId)
|
||||
{
|
||||
for (CreationsType::iterator i=m_creations.begin(); i!=m_creations.end(); ++i)
|
||||
{
|
||||
if (i->second->m_stage == CreationRecord::S_sentToGameServer && i->second->m_gameServerId==serverId)
|
||||
{
|
||||
i->second->m_stage = CreationRecord::S_queuedForGameServer;
|
||||
i->second->m_gameServerId = 0;
|
||||
LOG("TraceCharacterCreation", ("%d requeueing because game server disconnected", i->first));
|
||||
}
|
||||
}
|
||||
retryGameServerCreates();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::onLoginServerDisconnect(uint32 loginServerId)
|
||||
{
|
||||
for (CreationsType::iterator i=m_creations.begin(); i!=m_creations.end(); ++i)
|
||||
{
|
||||
if (i->second->m_stage == CreationRecord::S_sentToLoginServer && i->second->m_loginServerId==loginServerId)
|
||||
{
|
||||
i->second->m_stage = CreationRecord::S_queuedForLoginServer;
|
||||
i->second->m_loginServerId = 0;
|
||||
LOG("TraceCharacterCreation", ("%d requeueing because login server disconnected", i->first));
|
||||
}
|
||||
}
|
||||
retryLoginServerCreates();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::handleDatabaseCreateCharacterSuccess(StationId account, const Unicode::String &characterName, const NetworkId &characterObjectId, int templateId, bool jedi)
|
||||
{
|
||||
// - Check we are at the right stage
|
||||
LOG("TraceCharacterCreation", ("%d DatabaseCreateCharacterSuccess(%s)", account, characterObjectId.getValueString().c_str()));
|
||||
CreationsType::iterator creationRecord=m_creations.find(account);
|
||||
if (creationRecord==m_creations.end() || creationRecord->second->m_stage != CreationRecord::S_sentToGameServer)
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d DatabaseCreateCharacterSuccess was unexpected - exiting", account));
|
||||
DEBUG_WARNING(true,("Programmer bug: got GameCreateCharacter message for accout %d, which we weren't expecting.\n",account));
|
||||
return;
|
||||
}
|
||||
|
||||
// - Tell the login server to add the character
|
||||
LoginCreateCharacterMessage *msg = new LoginCreateCharacterMessage(account,characterName,characterObjectId,templateId,jedi);
|
||||
creationRecord->second->m_loginCreationRequest = msg;
|
||||
creationRecord->second->m_characterId = characterObjectId;
|
||||
uint32 loginServerId = CentralServer::getInstance().sendToArbitraryLoginServer(*msg, false);
|
||||
if (loginServerId != 0)
|
||||
{
|
||||
creationRecord->second->m_loginServerId = loginServerId;
|
||||
creationRecord->second->m_stage = CreationRecord::S_sentToLoginServer;
|
||||
LOG("TraceCharacterCreation", ("%d sending LoginCreateCharacterMessage", account));
|
||||
}
|
||||
else
|
||||
{
|
||||
creationRecord->second->m_loginServerId = 0;
|
||||
creationRecord->second->m_stage = CreationRecord::S_queuedForLoginServer;
|
||||
LOG("TraceCharacterCreation", ("%d waiting for login server", account));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::handleLoginCreateCharacterAck(StationId account)
|
||||
{
|
||||
// - Check we are at the right stage
|
||||
LOG("TraceCharacterCreation", ("%d LoginCreateCharacterAckMessage", account));
|
||||
CreationsType::iterator creationRecord=m_creations.find(account);
|
||||
if (creationRecord==m_creations.end() || creationRecord->second->m_stage != CreationRecord::S_sentToLoginServer)
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d LoginCreateCharacterAckMessage was unexpected - exiting", account));
|
||||
DEBUG_WARNING(true,("Programmer bug: got LoginCreateCharacterAckMessage message for account %d, which we weren't expecting.\n",account));
|
||||
return;
|
||||
}
|
||||
|
||||
// - Tell the client the character has been created
|
||||
LOG("TraceCharacterCreation", ("%d acknowledgeCharacterCreate(%s)", account, creationRecord->second->m_characterId.getValueString().c_str()));
|
||||
LOG("CustomerService", ("Player:created character %s for stationId %u", creationRecord->second->m_characterId.getValueString().c_str(), account));
|
||||
const ConnectionCreateCharacterSuccess c(account, creationRecord->second->m_characterId);
|
||||
CentralServer::getInstance().sendToConnectionServerForAccount(account, c, true);
|
||||
unlockAccount(account);
|
||||
|
||||
// let all connection servers know that a new character has been created for the station account
|
||||
GenericValueTypeMessage<StationId> const ncc("NewCharacterCreated", account);
|
||||
CentralServer::getInstance().sendToAllConnectionServers(ncc, true);
|
||||
|
||||
setFastCreationLock(account);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::handleGameCreateCharacterFailed(StationId account, Unicode::String const &characterName, StringId const &errorMessage, std::string const &optionalDetailedErrorMessage)
|
||||
{
|
||||
CreationsType::iterator creationRecord=m_creations.find(account);
|
||||
if (creationRecord==m_creations.end() || creationRecord->second->m_stage != CreationRecord::S_sentToGameServer)
|
||||
{
|
||||
LOG("TraceCharacterCreation", ("%d got handleGameCreateCharacterFailed, but we weren't in the sentToGameServer stage - ignoring", account));
|
||||
DEBUG_WARNING(true,("Programmer bug: got handleGameCreateCharacterFailed message for account %d, which we weren't expecting.\n",account));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("TraceCharacterCreation", ("%d received GameCreateCharacterFailed(%s)", account, Unicode::wideToNarrow(characterName).c_str()));
|
||||
ConnectionCreateCharacterFailed cccf(account, characterName, errorMessage, optionalDetailedErrorMessage);
|
||||
CentralServer::getInstance().sendToConnectionServerForAccount(account, cccf, true);
|
||||
unlockAccount(account);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void CharacterCreationTracker::setFastCreationLock(StationId account)
|
||||
{
|
||||
m_fastCreationLock[account]=Clock::timeSeconds();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
CharacterCreationTracker::CreationRecord::CreationRecord() :
|
||||
m_stage(S_queuedForGameServer),
|
||||
m_gameCreationRequest(NULL),
|
||||
m_loginCreationRequest(NULL),
|
||||
m_creationTime(ServerClock::getInstance().getGameTimeSeconds()),
|
||||
m_gameServerId(0),
|
||||
m_loginServerId(0),
|
||||
m_characterId(NetworkId::cms_invalid)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
CharacterCreationTracker::CreationRecord::~CreationRecord()
|
||||
{
|
||||
delete m_gameCreationRequest;
|
||||
delete m_loginCreationRequest;
|
||||
m_gameCreationRequest = 0;
|
||||
m_loginCreationRequest = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user