mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-13 19:18:21 +00:00
Pivot offline reclaim to world-owned flow
This commit is contained in:
@@ -37,10 +37,13 @@
|
||||
#include "common/races.h"
|
||||
#include "common/random.h"
|
||||
#include "common/repositories/account_repository.h"
|
||||
#include "common/repositories/buyer_repository.h"
|
||||
#include "common/repositories/character_data_repository.h"
|
||||
#include "common/repositories/group_id_repository.h"
|
||||
#include "common/repositories/inventory_repository.h"
|
||||
#include "common/repositories/offline_character_sessions_repository.h"
|
||||
#include "common/repositories/player_event_logs_repository.h"
|
||||
#include "common/repositories/trader_repository.h"
|
||||
#include "common/rulesys.h"
|
||||
#include "common/shareddb.h"
|
||||
#include "common/skill_caps.h"
|
||||
@@ -59,6 +62,7 @@
|
||||
|
||||
#include "zlib.h"
|
||||
#include <climits>
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -88,6 +92,60 @@ extern uint32 numclients;
|
||||
extern volatile bool RunLoops;
|
||||
extern volatile bool UCSServerAvailable_;
|
||||
|
||||
namespace {
|
||||
constexpr uint32 kOfflineSessionReclaimTimeoutMs = 10000;
|
||||
std::atomic<uint32> g_offline_reclaim_request_id{1};
|
||||
|
||||
uint8 ToOfflineSessionMode(const std::string &mode)
|
||||
{
|
||||
if (Strings::EqualFold(mode, "buyer")) {
|
||||
return OfflineSessionModeBuyer;
|
||||
}
|
||||
|
||||
if (Strings::EqualFold(mode, "trader")) {
|
||||
return OfflineSessionModeTrader;
|
||||
}
|
||||
|
||||
return OfflineSessionModeNone;
|
||||
}
|
||||
|
||||
const char *OfflineSessionModeName(uint8 mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OfflineSessionModeTrader:
|
||||
return "trader";
|
||||
case OfflineSessionModeBuyer:
|
||||
return "buyer";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char *OfflineSessionReclaimResponseName(int8 response)
|
||||
{
|
||||
switch (response) {
|
||||
case OfflineSessionReclaimSuccess:
|
||||
return "success";
|
||||
case OfflineSessionReclaimStale:
|
||||
return "stale";
|
||||
case OfflineSessionReclaimBusy:
|
||||
return "busy";
|
||||
default:
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
|
||||
uint32 NextOfflineReclaimRequestId()
|
||||
{
|
||||
auto request_id = g_offline_reclaim_request_id.fetch_add(1);
|
||||
if (request_id == 0) {
|
||||
request_id = g_offline_reclaim_request_id.fetch_add(1);
|
||||
}
|
||||
|
||||
return request_id;
|
||||
}
|
||||
}
|
||||
|
||||
// unused ATM, but here for reference, should match RoF2
|
||||
enum class NameApprovalResponse : int {
|
||||
NotValid = -1, // string ID 1576
|
||||
@@ -102,6 +160,7 @@ enum class NameApprovalResponse : int {
|
||||
Client::Client(EQStreamInterface* ieqs)
|
||||
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
|
||||
connect(1000),
|
||||
offline_reclaim_timeout(kOfflineSessionReclaimTimeoutMs),
|
||||
eqs(ieqs)
|
||||
{
|
||||
// Live does not send datarate as of 3/11/2005
|
||||
@@ -111,6 +170,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
|
||||
autobootup_timeout.Disable();
|
||||
connect.Disable();
|
||||
offline_reclaim_timeout.Disable();
|
||||
seen_character_select = false;
|
||||
cle = 0;
|
||||
zone_id = 0;
|
||||
@@ -119,6 +179,14 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
zone_waiting_for_bootup = 0;
|
||||
enter_world_triggered = false;
|
||||
StartInTutorial = false;
|
||||
offline_reclaim_pending = false;
|
||||
offline_reclaim_request_id = 0;
|
||||
offline_reclaim_character_id = 0;
|
||||
offline_reclaim_zone_id = 0;
|
||||
offline_reclaim_instance_id = 0;
|
||||
offline_reclaim_entity_id = 0;
|
||||
offline_reclaim_started_at = 0;
|
||||
offline_reclaim_mode = OfflineSessionModeNone;
|
||||
|
||||
m_ClientVersion = eqs->ClientVersion();
|
||||
m_ClientVersionBit = EQ::versions::ConvertClientVersionToClientVersionBit(m_ClientVersion);
|
||||
@@ -932,6 +1000,17 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!BeginOfflineSessionReclaimIfNeeded()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ContinueEnterWorld();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::ContinueEnterWorld()
|
||||
{
|
||||
if(!is_player_zoning) {
|
||||
GroupIdRepository::DeleteWhere(
|
||||
database,
|
||||
@@ -1066,10 +1145,201 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
EnterWorld();
|
||||
}
|
||||
|
||||
bool Client::BeginOfflineSessionReclaimIfNeeded()
|
||||
{
|
||||
if (offline_reclaim_pending) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto session = OfflineCharacterSessionsRepository::GetByAccountId(database, GetAccountID());
|
||||
if (!session.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto mode = ToOfflineSessionMode(session.mode);
|
||||
if (mode == OfflineSessionModeNone) {
|
||||
LogWarning(
|
||||
"Character entry for [{}] account [{}] found offline session with unexpected mode [{}]; attempting targeted reclaim using stored zone and entity metadata",
|
||||
GetCharName(),
|
||||
GetAccountID(),
|
||||
session.mode
|
||||
);
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Character entry for [{}] account [{}] found offline {} session character_id [{}] zone_id [{}] instance_id [{}] entity_id [{}]",
|
||||
GetCharName(),
|
||||
GetAccountID(),
|
||||
OfflineSessionModeName(mode),
|
||||
session.character_id,
|
||||
session.zone_id,
|
||||
session.instance_id,
|
||||
session.entity_id
|
||||
);
|
||||
|
||||
auto zone_server = session.instance_id > 0 ?
|
||||
ZSList::Instance()->FindByInstanceID(session.instance_id) :
|
||||
ZSList::Instance()->FindByZoneID(session.zone_id);
|
||||
|
||||
if (!zone_server || !zone_server->IsConnected()) {
|
||||
auto clear_started_at = Timer::GetCurrentTime();
|
||||
if (!ClearStaleOfflineSession(session.character_id, "zone not booted")) {
|
||||
LogError(
|
||||
"Failed clearing stale offline {} session locally for account [{}] character [{}]",
|
||||
OfflineSessionModeName(mode),
|
||||
GetAccountID(),
|
||||
session.character_id
|
||||
);
|
||||
TellClientZoneUnavailable();
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Cleared stale offline {} session locally for account [{}] character [{}] in [{}] ms",
|
||||
OfflineSessionModeName(mode),
|
||||
GetAccountID(),
|
||||
session.character_id,
|
||||
Timer::GetCurrentTime() - clear_started_at
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_ReclaimOfflineSessionReq, sizeof(OfflineSessionReclaim_Struct));
|
||||
auto reclaim = reinterpret_cast<OfflineSessionReclaim_Struct *>(pack->pBuffer);
|
||||
memset(pack->pBuffer, 0, pack->size);
|
||||
|
||||
offline_reclaim_pending = true;
|
||||
offline_reclaim_request_id = NextOfflineReclaimRequestId();
|
||||
offline_reclaim_character_id = session.character_id;
|
||||
offline_reclaim_zone_id = session.zone_id;
|
||||
offline_reclaim_instance_id = session.instance_id;
|
||||
offline_reclaim_entity_id = session.entity_id;
|
||||
offline_reclaim_started_at = Timer::GetCurrentTime();
|
||||
offline_reclaim_mode = mode;
|
||||
offline_reclaim_timeout.Start(kOfflineSessionReclaimTimeoutMs);
|
||||
|
||||
reclaim->request_id = offline_reclaim_request_id;
|
||||
reclaim->account_id = GetAccountID();
|
||||
reclaim->character_id = session.character_id;
|
||||
reclaim->zone_id = session.zone_id;
|
||||
reclaim->instance_id = session.instance_id;
|
||||
reclaim->entity_id = session.entity_id;
|
||||
reclaim->mode = mode;
|
||||
reclaim->response = OfflineSessionReclaimFailed;
|
||||
|
||||
LogInfo(
|
||||
"Sending targeted offline {} reclaim request [{}] to zone [{}] instance [{}] for account [{}]",
|
||||
OfflineSessionModeName(mode),
|
||||
offline_reclaim_request_id,
|
||||
session.zone_id,
|
||||
session.instance_id,
|
||||
GetAccountID()
|
||||
);
|
||||
|
||||
zone_server->SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::ClearStaleOfflineSession(uint32 character_id, const char *reason)
|
||||
{
|
||||
database.TransactionBegin();
|
||||
AccountRepository::SetOfflineStatus(database, GetAccountID(), false);
|
||||
OfflineCharacterSessionsRepository::DeleteByAccountId(database, GetAccountID());
|
||||
|
||||
if (character_id) {
|
||||
TraderRepository::DeleteWhere(database, fmt::format("`character_id` = {}", character_id));
|
||||
BuyerRepository::DeleteBuyer(database, character_id);
|
||||
}
|
||||
|
||||
auto commit_result = database.TransactionCommit();
|
||||
if (!commit_result.Success()) {
|
||||
database.TransactionRollback();
|
||||
LogError(
|
||||
"Failed clearing stale offline session for account [{}] character [{}] while {}: ({}) {}",
|
||||
GetAccountID(),
|
||||
character_id,
|
||||
reason ? reason : "processing entry",
|
||||
commit_result.ErrorNumber(),
|
||||
commit_result.ErrorMessage()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::ResetOfflineSessionReclaimState()
|
||||
{
|
||||
offline_reclaim_timeout.Disable();
|
||||
offline_reclaim_pending = false;
|
||||
offline_reclaim_request_id = 0;
|
||||
offline_reclaim_character_id = 0;
|
||||
offline_reclaim_zone_id = 0;
|
||||
offline_reclaim_instance_id = 0;
|
||||
offline_reclaim_entity_id = 0;
|
||||
offline_reclaim_started_at = 0;
|
||||
offline_reclaim_mode = OfflineSessionModeNone;
|
||||
}
|
||||
|
||||
void Client::HandleOfflineSessionReclaimResponse(const OfflineSessionReclaim_Struct &response)
|
||||
{
|
||||
if (!offline_reclaim_pending) {
|
||||
LogInfo(
|
||||
"Ignoring offline reclaim response [{}] for account [{}] because no reclaim is pending",
|
||||
response.request_id,
|
||||
response.account_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.request_id != offline_reclaim_request_id) {
|
||||
LogInfo(
|
||||
"Ignoring stale offline reclaim response [{}] for account [{}]; current request is [{}]",
|
||||
response.request_id,
|
||||
response.account_id,
|
||||
offline_reclaim_request_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto elapsed_ms = Timer::GetCurrentTime() - offline_reclaim_started_at;
|
||||
|
||||
LogInfo(
|
||||
"Received offline {} reclaim response [{}] status [{}] after [{}] ms for account [{}]",
|
||||
OfflineSessionModeName(offline_reclaim_mode),
|
||||
response.request_id,
|
||||
OfflineSessionReclaimResponseName(response.response),
|
||||
elapsed_ms,
|
||||
response.account_id
|
||||
);
|
||||
|
||||
if (response.response == OfflineSessionReclaimSuccess) {
|
||||
ResetOfflineSessionReclaimState();
|
||||
ContinueEnterWorld();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.response == OfflineSessionReclaimStale) {
|
||||
auto clear_started_at = Timer::GetCurrentTime();
|
||||
if (ClearStaleOfflineSession(offline_reclaim_character_id, "zone confirmed stale session")) {
|
||||
LogInfo(
|
||||
"Cleared stale offline {} session for account [{}] after zone confirmation in [{}] ms",
|
||||
OfflineSessionModeName(offline_reclaim_mode),
|
||||
GetAccountID(),
|
||||
Timer::GetCurrentTime() - clear_started_at
|
||||
);
|
||||
ResetOfflineSessionReclaimState();
|
||||
ContinueEnterWorld();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TellClientZoneUnavailable();
|
||||
}
|
||||
|
||||
bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) {
|
||||
|
||||
uint32 char_acct_id = database.GetAccountIDByChar((char*)app->pBuffer);
|
||||
@@ -1223,6 +1493,18 @@ bool Client::Process() {
|
||||
TellClientZoneUnavailable();
|
||||
}
|
||||
|
||||
if (offline_reclaim_pending && offline_reclaim_timeout.Check()) {
|
||||
auto elapsed_ms = Timer::GetCurrentTime() - offline_reclaim_started_at;
|
||||
LogWarning(
|
||||
"Offline {} reclaim timed out after [{}] ms for account [{}] selected character [{}]",
|
||||
OfflineSessionModeName(offline_reclaim_mode),
|
||||
elapsed_ms,
|
||||
GetAccountID(),
|
||||
GetCharName()
|
||||
);
|
||||
TellClientZoneUnavailable();
|
||||
}
|
||||
|
||||
if(connect.Check()){
|
||||
SendGuildList();// Send OPCode: OP_GuildsList
|
||||
SendApproveWorld();
|
||||
@@ -1601,6 +1883,7 @@ void Client::TellClientZoneUnavailable() {
|
||||
zone_waiting_for_bootup = 0;
|
||||
enter_world_triggered = false;
|
||||
autobootup_timeout.Disable();
|
||||
ResetOfflineSessionReclaimState();
|
||||
}
|
||||
|
||||
void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req) {
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
void SendPostEnterWorld();
|
||||
void SendGuildTributeFavorAndTimer(uint32 favor, uint32 time_remaining);
|
||||
void SendGuildTributeOptInToggle(const GuildTributeMemberToggle* in);
|
||||
void HandleOfflineSessionReclaimResponse(const OfflineSessionReclaim_Struct &response);
|
||||
|
||||
inline uint32 GetIP() { return ip; }
|
||||
inline uint16 GetPort() { return port; }
|
||||
@@ -100,6 +101,15 @@ private:
|
||||
ClientListEntry* cle;
|
||||
Timer connect;
|
||||
bool seen_character_select;
|
||||
Timer offline_reclaim_timeout;
|
||||
bool offline_reclaim_pending;
|
||||
uint32 offline_reclaim_request_id;
|
||||
uint32 offline_reclaim_character_id;
|
||||
uint32 offline_reclaim_zone_id;
|
||||
int32 offline_reclaim_instance_id;
|
||||
uint32 offline_reclaim_entity_id;
|
||||
uint32 offline_reclaim_started_at;
|
||||
uint8 offline_reclaim_mode;
|
||||
|
||||
bool HandlePacket(const EQApplicationPacket *app);
|
||||
bool HandleNameApprovalPacket(const EQApplicationPacket *app);
|
||||
@@ -114,6 +124,10 @@ private:
|
||||
bool ChecksumVerificationCRCEQGame(uint64 checksum);
|
||||
bool ChecksumVerificationCRCSkillCaps(uint64 checksum);
|
||||
bool ChecksumVerificationCRCBaseData(uint64 checksum);
|
||||
void ContinueEnterWorld();
|
||||
bool BeginOfflineSessionReclaimIfNeeded();
|
||||
bool ClearStaleOfflineSession(uint32 character_id, const char *reason);
|
||||
void ResetOfflineSessionReclaimState();
|
||||
|
||||
EQStreamInterface* eqs;
|
||||
bool CanTradeFVNoDropItem();
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
#include "common/eqemu_logsys.h"
|
||||
#include "common/misc_functions.h"
|
||||
#include "common/packet_dump.h"
|
||||
#include "common/repositories/account_repository.h"
|
||||
#include "common/repositories/buyer_repository.h"
|
||||
#include "common/repositories/character_data_repository.h"
|
||||
#include "common/repositories/offline_character_sessions_repository.h"
|
||||
#include "common/repositories/trader_repository.h"
|
||||
#include "common/servertalk.h"
|
||||
#include "common/strings.h"
|
||||
#include "common/version.h"
|
||||
@@ -195,13 +190,6 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
||||
return;
|
||||
}
|
||||
|
||||
if (status_record.offline || OfflineCharacterSessionsRepository::ExistsByAccountId(database, id)) {
|
||||
LogDebug("User has an offline character for account_id [{0}]", utwr->lsaccountid);
|
||||
utwrs->response = UserToWorldStatusOffilineTraderBuyer;
|
||||
SendPacket(&outpack);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuleB(World, EnforceCharacterLimitAtLogin)) {
|
||||
if (ClientList::Instance()->IsAccountInGame(utwr->lsaccountid)) {
|
||||
LogDebug("User already online account_id [{0}]", utwr->lsaccountid);
|
||||
@@ -589,14 +577,6 @@ bool LoginServer::Connect()
|
||||
std::placeholders::_2
|
||||
)
|
||||
);
|
||||
m_client->OnMessage(
|
||||
ServerOP_UsertoWorldCancelOfflineRequest,
|
||||
std::bind(
|
||||
&LoginServer::ProcessUserToWorldCancelOfflineRequest,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -711,109 +691,3 @@ void LoginServer::SendAccountUpdate(ServerPacket *pack)
|
||||
SendPacket(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void LoginServer::ProcessUserToWorldCancelOfflineRequest(uint16_t opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
auto const Config = WorldConfig::get();
|
||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||
|
||||
auto utwr = static_cast<UsertoWorldRequest *>(p.Data());
|
||||
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
||||
auto status_record = database.GetAccountStatus(id);
|
||||
|
||||
LogLoginserverDetail(
|
||||
"Step 4 - World received CancelOfflineRequest for client login server account id {} offline mode {}",
|
||||
id,
|
||||
status_record.offline
|
||||
);
|
||||
LogDebug(
|
||||
"id [{}] status [{}] account_id [{}] world_id [{}] ip [{}]",
|
||||
id,
|
||||
status_record.status,
|
||||
utwr->lsaccountid,
|
||||
utwr->worldid,
|
||||
utwr->IPAddr
|
||||
);
|
||||
|
||||
ServerPacket server_packet;
|
||||
server_packet.size = sizeof(UsertoWorldResponse);
|
||||
server_packet.pBuffer = new uchar[server_packet.size];
|
||||
memset(server_packet.pBuffer, 0, server_packet.size);
|
||||
|
||||
auto utwrs = reinterpret_cast<UsertoWorldResponse *>(server_packet.pBuffer);
|
||||
utwrs->lsaccountid = utwr->lsaccountid;
|
||||
utwrs->ToID = utwr->FromID;
|
||||
utwrs->worldid = utwr->worldid;
|
||||
utwrs->response = UserToWorldStatusSuccess;
|
||||
strn0cpy(utwrs->login, utwr->login, 64);
|
||||
|
||||
if (Config->Locked == true) {
|
||||
if (status_record.status < RuleI(GM, MinStatusToBypassLockedServer)) {
|
||||
LogDebug("Server locked and status is not high enough for account_id [{0}]", utwr->lsaccountid);
|
||||
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
utwrs->response = UserToWorldStatusWorldUnavail;
|
||||
SendPacket(&server_packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32 x = Config->MaxClients;
|
||||
if (static_cast<int32>(numplayers) >= x &&
|
||||
x != -1 &&
|
||||
x != 255 &&
|
||||
status_record.status < RuleI(GM, MinStatusToBypassLockedServer)
|
||||
) {
|
||||
LogDebug("World at capacity account_id [{0}]", utwr->lsaccountid);
|
||||
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
utwrs->response = UserToWorldStatusWorldAtCapacity;
|
||||
SendPacket(&server_packet);
|
||||
return;
|
||||
}
|
||||
|
||||
auto session = OfflineCharacterSessionsRepository::GetByAccountId(database, id);
|
||||
auto trader = TraderRepository::GetAccountZoneIdAndInstanceIdByAccountId(database, id);
|
||||
uint32 zone_id = session.id ? session.zone_id : trader.char_zone_id;
|
||||
int32 instance_id = session.id ? session.instance_id : trader.char_zone_instance_id;
|
||||
uint32 character_id = session.id ? session.character_id : trader.character_id;
|
||||
|
||||
if ((session.id || trader.id) &&
|
||||
ZSList::Instance()->IsZoneBootedByZoneIdAndInstanceId(zone_id, instance_id)) {
|
||||
LogLoginserverDetail(
|
||||
"Step 5a(1) - World Checked offline users zone/instance is booted. "
|
||||
"Sending packet to zone id {} instance id {}",
|
||||
zone_id,
|
||||
instance_id);
|
||||
|
||||
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineRequest;
|
||||
ZSList::Instance()->SendPacketToBootedZones(&server_packet);
|
||||
return;
|
||||
}
|
||||
|
||||
LogLoginserverDetail("Step 5b(1) - World determined offline users zone/instance is not booted. Ignoring zone.");
|
||||
|
||||
LogLoginserverDetail("Step 5b(2) - World clearing users offline status from account table.");
|
||||
database.TransactionBegin();
|
||||
AccountRepository::SetOfflineStatus(database, id, false);
|
||||
OfflineCharacterSessionsRepository::DeleteByAccountId(database, id);
|
||||
|
||||
LogLoginserverDetail("Step 5b(3) - World clearing trader and buyer tables.");
|
||||
if (character_id) {
|
||||
TraderRepository::DeleteWhere(database, fmt::format("`character_id` = '{}'", character_id));
|
||||
BuyerRepository::DeleteBuyer(database, character_id);
|
||||
}
|
||||
|
||||
auto commit_result = database.TransactionCommit();
|
||||
if (!commit_result.Success()) {
|
||||
database.TransactionRollback();
|
||||
LogError(
|
||||
"Failed clearing offline session state for account [{}]: ({}) {}",
|
||||
id,
|
||||
commit_result.ErrorNumber(),
|
||||
commit_result.ErrorMessage()
|
||||
);
|
||||
utwrs->response = UserToWorldStatusWorldUnavail;
|
||||
}
|
||||
|
||||
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
SendPacket(&server_packet);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ private:
|
||||
void ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void ProcessLSAccountUpdate(uint16_t opcode, EQ::Net::Packet &p);
|
||||
void ProcessUserToWorldCancelOfflineRequest(uint16_t opcode, EQ::Net::Packet &p);
|
||||
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
|
||||
|
||||
+16
-19
@@ -779,6 +779,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
if (client) {
|
||||
client->Clearance(wtz->response);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZoneToZoneRequest: {
|
||||
// ZoneChange is received by the zone the player is in, then the
|
||||
@@ -1733,27 +1734,23 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_UsertoWorldCancelOfflineResponse: {
|
||||
auto utwr = reinterpret_cast<UsertoWorldResponse *>(pack->pBuffer);
|
||||
case ServerOP_ReclaimOfflineSessionResp: {
|
||||
if (pack->size != sizeof(OfflineSessionReclaim_Struct)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ServerPacket server_packet;
|
||||
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
|
||||
server_packet.size = sizeof(UsertoWorldResponse);
|
||||
server_packet.pBuffer = new uchar[server_packet.size];
|
||||
memset(server_packet.pBuffer, 0, server_packet.size);
|
||||
auto reclaim = reinterpret_cast<OfflineSessionReclaim_Struct *>(pack->pBuffer);
|
||||
auto client = ClientList::Instance()->FindByAccountID(reclaim->account_id);
|
||||
if (!client) {
|
||||
LogInfo(
|
||||
"Ignoring offline reclaim response [{}] for account [{}]; world client not found",
|
||||
reclaim->request_id,
|
||||
reclaim->account_id
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
auto utwrs = reinterpret_cast<UsertoWorldResponse *>(server_packet.pBuffer);
|
||||
utwrs->lsaccountid = utwr->lsaccountid;
|
||||
utwrs->ToID = utwr->FromID;
|
||||
utwrs->worldid = utwr->worldid;
|
||||
utwrs->response = UserToWorldStatusSuccess;
|
||||
strn0cpy(utwrs->login, utwr->login, 64);
|
||||
|
||||
LogLoginserverDetail(
|
||||
"Step 7a - World received ServerOP_UsertoWorldCancelOfflineResponse back to login with success."
|
||||
);
|
||||
|
||||
LoginServerList::Instance()->SendPacket(&server_packet);
|
||||
client->HandleOfflineSessionReclaimResponse(*reclaim);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
Reference in New Issue
Block a user