Phase 1 Offline Trading

Cleanup and testing
Zone updated builds ok
World updated builds ok

Update guild_base.h
This commit is contained in:
Mitch Freeman
2025-03-22 08:39:53 -03:00
parent a81ec11ea3
commit cf3b9638c9
50 changed files with 1777 additions and 229 deletions
+11
View File
@@ -202,6 +202,9 @@ void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, CLE_
m_lfg = scl->LFG;
m_gm = scl->gm;
m_client_version = scl->ClientVersion;
m_trader = scl->trader;
m_buyer = scl->buyer;
m_offline = scl->offline;
// Fields from the LFG Window
if ((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
@@ -219,6 +222,10 @@ void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
if (iZS != 0 && iZS != m_zone_server) {
return;
}
m_trader = false;
m_buyer = false;
m_offline = false;
SetOnline(iOnline);
SharedTaskManager::Instance()->RemoveActiveInvitationByCharacterID(CharID());
@@ -260,6 +267,10 @@ void ClientListEntry::ClearVars(bool iAll)
m_lfg = 0;
m_gm = 0;
m_client_version = 0;
m_trader = false;
m_buyer = false;
m_offline = false;
for (auto &elem: m_tell_queue) {
safe_delete_array(elem);
}
+30 -21
View File
@@ -14,7 +14,8 @@ typedef enum {
Online,
CharSelect,
Zoning,
InZone
InZone,
OfflineMode
} CLE_Status;
static const char *CLEStatusString[] = {
@@ -23,7 +24,8 @@ static const char *CLEStatusString[] = {
"Online",
"CharSelect",
"Zoning",
"InZone"
"InZone",
"OfflineMode"
};
class ZoneServer;
@@ -103,6 +105,10 @@ public:
inline bool GetLFGMatchFilter() const { return m_lfg_match_filter; }
inline const char *GetLFGComments() const { return m_lfg_comments; }
inline uint8 GetClientVersion() { return m_client_version; }
bool GetTrader() const { return m_trader; }
bool GetBuyer() const { return m_buyer; }
bool GetOfflineMode() const { return m_offline; }
void SetOfflineMode(bool status) { m_offline = status; }
inline bool TellQueueFull() const { return m_tell_queue.size() >= RuleI(World, TellQueueSize); }
inline bool TellQueueEmpty() const { return m_tell_queue.empty(); }
@@ -135,25 +141,28 @@ private:
// Character info
ZoneServer *m_zone_server{};
uint32 m_zone{};
uint16 m_instance{};
uint32 m_char_id{};
char m_char_name[64]{};
uint8 m_level{};
uint8 m_class_{};
uint16 m_race{};
uint8 m_anon{};
uint8 m_tells_off{};
uint32 m_guild_id{};
uint32 m_guild_rank;
bool m_guild_tribute_opt_in{};
bool m_lfg{};
uint8 m_gm{};
uint8 m_client_version{};
uint8 m_lfg_from_level{};
uint8 m_lfg_to_level{};
bool m_lfg_match_filter{};
char m_lfg_comments[64]{};
uint32 m_zone{};
uint16 m_instance{};
uint32 m_char_id{};
char m_char_name[64]{};
uint8 m_level{};
uint8 m_class_{};
uint16 m_race{};
uint8 m_anon{};
uint8 m_tells_off{};
uint32 m_guild_id{};
uint32 m_guild_rank;
bool m_guild_tribute_opt_in{};
bool m_lfg{};
uint8 m_gm{};
uint8 m_client_version{};
uint8 m_lfg_from_level{};
uint8 m_lfg_to_level{};
bool m_lfg_match_filter{};
char m_lfg_comments[64]{};
bool m_trader = false;
bool m_buyer = false;
bool m_offline = false;
// Tell Queue -- really a vector :D
std::vector<ServerChannelMessage_Struct *> m_tell_queue;
+58 -22
View File
@@ -427,7 +427,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
while (iterator.MoreElements()) {
if (iterator.GetData()->GetID() == scl->wid) {
cle = iterator.GetData();
if (scl->remove == 2) {
if (scl->remove == 3) {
cle->Update(zoneserver, scl, CLE_Status::OfflineMode);
}
else if (scl->remove == 2) {
cle->LeavingZone(zoneserver, CLE_Status::Offline);
}
else if (scl->remove == 1) {
@@ -441,7 +444,11 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
}
iterator.Advance();
}
if (scl->remove == 2) {
if (scl->remove == 3) {
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::OfflineMode);
}
else if (scl->remove == 2) {
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Online);
}
else if (scl->remove == 1) {
@@ -479,7 +486,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
" LFGFromLevel [{}]"
" LFGToLevel [{}]"
" LFGMatchFilter [{}]"
" LFGComments [{}]",
" LFGComments [{}]"
" Trader [{}]"
" Buyer [{}]"
" Offline [{}]",
scl->remove,
scl->wid,
scl->IP,
@@ -506,7 +516,10 @@ void ClientList::ClientUpdate(ZoneServer *zoneserver, ServerClientList_Struct *s
scl->LFGFromLevel,
scl->LFGToLevel,
scl->LFGMatchFilter,
scl->LFGComments
scl->LFGComments,
scl->trader,
scl->buyer,
scl->offline
);
clientlist.Insert(cle);
@@ -784,7 +797,14 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
rankstring = 0;
iterator.Advance();
continue;
} else if (cle->GetGM()) {
}
else if (cle->GetTrader()) {
rankstring = 12315;
}
else if (cle->GetBuyer()) {
rankstring = 6056;
}
else if (cle->GetGM()) {
if (cle->Admin() >= AccountStatus::GMImpossible) {
rankstring = 5021;
} else if (cle->Admin() >= AccountStatus::GMMgmt) {
@@ -877,6 +897,18 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
strcpy(placcount,cle->AccountName());
}
if (cle->GetOfflineMode()) {
if (cle->GetTrader()) {
pidstring = 0x0430;
rankstring = 0xFFFFFFFF;
}
if (cle->GetBuyer()) {
pidstring = 0x0420;
rankstring = 0xFFFFFFFF;
}
}
memcpy(bufptr,&formatstring, sizeof(uint32));
bufptr+=sizeof(uint32);
memcpy(bufptr,&pidstring, sizeof(uint32));
@@ -1631,25 +1663,29 @@ void ClientList::OnTick(EQ::Timer *t)
outclient["Server"] = Json::Value();
}
outclient["CharID"] = cle->CharID();
outclient["name"] = cle->name();
outclient["zone"] = cle->zone();
outclient["instance"] = cle->instance();
outclient["level"] = cle->level();
outclient["class_"] = cle->class_();
outclient["race"] = cle->race();
outclient["Anon"] = cle->Anon();
outclient["CharID"] = cle->CharID();
outclient["name"] = cle->name();
outclient["zone"] = cle->zone();
outclient["instance"] = cle->instance();
outclient["level"] = cle->level();
outclient["class_"] = cle->class_();
outclient["race"] = cle->race();
outclient["Anon"] = cle->Anon();
outclient["TellsOff"] = cle->TellsOff();
outclient["GuildID"] = cle->GuildID();
outclient["LFG"] = cle->LFG();
outclient["GM"] = cle->GetGM();
outclient["LocalClient"] = cle->IsLocalClient();
outclient["LFGFromLevel"] = cle->GetLFGFromLevel();
outclient["LFGToLevel"] = cle->GetLFGToLevel();
outclient["TellsOff"] = cle->TellsOff();
outclient["GuildID"] = cle->GuildID();
outclient["LFG"] = cle->LFG();
outclient["GM"] = cle->GetGM();
outclient["LocalClient"] = cle->IsLocalClient();
outclient["LFGFromLevel"] = cle->GetLFGFromLevel();
outclient["LFGToLevel"] = cle->GetLFGToLevel();
outclient["LFGMatchFilter"] = cle->GetLFGMatchFilter();
outclient["LFGComments"] = cle->GetLFGComments();
outclient["ClientVersion"] = cle->GetClientVersion();
outclient["LFGComments"] = cle->GetLFGComments();
outclient["ClientVersion"] = cle->GetClientVersion();
outclient["Trader"] = cle->GetTrader();
outclient["Buyer"] = cle->GetBuyer();
outclient["OfflineMode"] = cle->GetOfflineMode();
out["data"].append(outclient);
Iterator.Advance();
+1 -1
View File
@@ -56,7 +56,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const
const std::string& account_name = database.GetAccountName(ret.account_id);
ret.account_name = account_name;
ret.status = database.GetAccountStatus(ret.account_id);
ret.status = database.GetAccountStatus(ret.account_id).status;
return ret;
}
+136 -28
View File
@@ -1,24 +1,28 @@
#include "../common/global_define.h"
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <iomanip>
#include <stdlib.h>
#include "../common/version.h"
#include "../common/servertalk.h"
#include "../common/misc_functions.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "../common/strings.h"
#include "../common/eqemu_logsys.h"
#include "login_server.h"
#include <iomanip>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../common/eq_packet_structs.h"
#include "../common/eqemu_logsys.h"
#include "../common/global_define.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/trader_repository.h"
#include "../common/servertalk.h"
#include "../common/strings.h"
#include "../common/version.h"
#include "cliententry.h"
#include "clientlist.h"
#include "login_server_list.h"
#include "zoneserver.h"
#include "world_config.h"
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "cliententry.h"
#include "world_config.h"
#include "zoneserver.h"
extern uint32 numzones;
extern uint32 numplayers;
@@ -44,9 +48,9 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
const WorldConfig *Config = WorldConfig::get();
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
UsertoWorldRequestLegacy *utwr = (UsertoWorldRequestLegacy *) p.Data();
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
int16 status = database.GetAccountStatus(id);
UsertoWorldRequestLegacy *utwr = (UsertoWorldRequestLegacy *) p.Data();
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
int16 status = database.GetAccountStatus(id).status;
LogDebug(
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
@@ -124,14 +128,19 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
const WorldConfig *Config = WorldConfig::get();
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
UsertoWorldRequest *utwr = (UsertoWorldRequest *) p.Data();
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
int16 status = database.GetAccountStatus(id);
UsertoWorldRequest *utwr = (UsertoWorldRequest *) p.Data();
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
auto status_record = database.GetAccountStatus(id);
auto client = client_list.FindCLEByAccountID(id);
if (client) {
client->SetOfflineMode(status_record.offline);
}
LogDebug(
"id [{}] status [{}] account_id [{}] world_id [{}] from_id [{}] to_id [{}] ip [{}]",
id,
status,
status_record.status,
utwr->lsaccountid,
utwr->worldid,
utwr->FromID,
@@ -153,7 +162,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
utwrs->response = UserToWorldStatusSuccess;
if (Config->Locked == true) {
if (status < (RuleI(GM, MinStatusToBypassLockedServer))) {
if (status_record.status < (RuleI(GM, MinStatusToBypassLockedServer))) {
LogDebug(
"Server locked and status is not high enough for account_id [{0}]",
utwr->lsaccountid
@@ -165,27 +174,34 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
}
int32 x = Config->MaxClients;
if ((int32) numplayers >= x && x != -1 && x != 255 && status < (RuleI(GM, MinStatusToBypassLockedServer))) {
if ((int32) numplayers >= x && x != -1 && x != 255 && status_record.status < (RuleI(GM, MinStatusToBypassLockedServer))) {
LogDebug("World at capacity account_id [{0}]", utwr->lsaccountid);
utwrs->response = UserToWorldStatusWorldAtCapacity;
SendPacket(&outpack);
return;
}
if (status == -1) {
if (status_record.status == -1) {
LogDebug("User suspended account_id [{0}]", utwr->lsaccountid);
utwrs->response = UserToWorldStatusSuspended;
SendPacket(&outpack);
return;
}
if (status == -2) {
if (status_record.status == -2) {
LogDebug("User banned account_id [{0}]", utwr->lsaccountid);
utwrs->response = UserToWorldStatusBanned;
SendPacket(&outpack);
return;
}
if (status_record.offline) {
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);
@@ -573,6 +589,14 @@ bool LoginServer::Connect()
std::placeholders::_2
)
);
m_client->OnMessage(
ServerOP_UsertoWorldCancelOfflineRequest,
std::bind(
&LoginServer::ProcessUserToWorldCancelOfflineRequest,
this,
std::placeholders::_1,
std::placeholders::_2)
);
}
return true;
@@ -688,3 +712,87 @@ void LoginServer::SendAccountUpdate(ServerPacket *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 trader = TraderRepository::GetAccountZoneIdAndInstanceIdByAccountId(database, id);
if (trader.id &&
zoneserver_list.IsZoneBootedByZoneIdAndInstanceId(trader.char_zone_id, trader.char_zone_instance_id)) {
LogLoginserverDetail(
"Step 5a(1) - World Checked offline users zone/instance is booted. "
"Sending packet to zone id {} instance id {}",
trader.char_zone_id,
trader.char_zone_instance_id);
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineRequest;
zoneserver_list.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.");
AccountRepository::SetOfflineStatus(database, id, false);
LogLoginserverDetail("Step 5b(3) - World clearing trader and buyer tablese.");
TraderRepository::DeleteWhere(database, fmt::format("`char_id` = '{}'", trader.id));
BuyerRepository::DeleteBuyer(database, trader.id);
server_packet.opcode = ServerOP_UsertoWorldCancelOfflineResponse;
SendPacket(&server_packet);
}
+1
View File
@@ -49,6 +49,7 @@ 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;
+12
View File
@@ -1018,3 +1018,15 @@ void ZSList::QueueServerReload(ServerReload::Type &type)
m_queued_reloads.emplace_back(type);
m_queued_reloads_mutex.unlock();
}
bool ZSList::IsZoneBootedByZoneIdAndInstanceId(uint32 zone_id, uint32 instance_id) const
{
for (auto const& z : zone_server_list) {
auto r = z.get();
if (r && r->GetZoneID() == zone_id && r->GetInstanceID() == instance_id) {
return true;
}
}
return false;
}
+1
View File
@@ -34,6 +34,7 @@ public:
bool SendPacketToZonesWithGMs(ServerPacket *pack);
bool SendPacketToBootedZones(ServerPacket* pack);
bool SetLockedZone(uint16 iZoneID, bool iLock);
bool IsZoneBootedByZoneIdAndInstanceId(uint32 zone_id, uint32 instance_id) const;
EQTime worldclock;
+27 -2
View File
@@ -1726,9 +1726,34 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break;
}
default:
return;
default: {
break;
}
}
break;
}
case ServerOP_UsertoWorldCancelOfflineResponse: {
auto utwr = reinterpret_cast<UsertoWorldResponse *>(pack->pBuffer);
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 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.SendPacket(&server_packet);
break;
}
default: {
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);