Dual Login Server Code
Secrets: I cant find your original Dual Login server code, so here's what I wanted to add on to it, as it's a continuation of what you did. This has been working fine and I've had it it on since I saw your post a while back.
In summary, here's what happens; first i wanted to maintain separate ID records of my users, so I added another table to table account and called it lsaccount_id2. This is what I have on my notes so has two alterations;
Code:
ALTER TABLE `account` ADD `lsaccount_id2` int(10) UNSIGNED DEFAULT '0'AFTER `lsaccount_id`;
ALTER TABLE `ax_classic`.`account` MODIFY COLUMN `lsaccount_id2` INT(10) UNSIGNED DEFAULT 0;
Since account already had all the users, and I needed one table to start at a higher increment, I converted the original account table;
Code:
UPDATE ax_classic.account SET lsaccount_id=lsaccount_id +5000000 WHERE lsaccount_id > 0;
And my accounts on my LS to match;
Code:
UPDATE new_login.login_accounts SET id=id +5000000;
so now I have my LS and accounts pointed to anything 5000000 or above, and anything below 5000000, must be from EqEmu- I don't think EqEmu will reach 5000000 during my lifetime, but if it did, then just up the increment to my LS accounts.
I have two sets of code, one that I have in use, but since it is sort of "hackish", i wanted one that was true in all areas, one that would monitor and single out/specify each port. But it is a lot of work that goes into a lot of code (and the work is triple for me, because I never know what I'm doing most the time), I got burnt out an put it on my "ToDo" list.
Here's the code I currently use, changes to LS are quoted with DUAL_SERVER, so you can easily pull them out and add them to your code, I posted the whole pages of script, cause diffs won't work with this code, it has other custom stuff, but you can see where the Dual LS code is placed ( #ifdef DUAL_SERVER);
LoginServer.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include <stdlib.h>
#include "../common/version.h"
#ifdef WIN32
#include <process.h>
#include <windows.h>
#include <winsock.h>
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else // Pyro: fix for linux
#include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include "../common/unix.h"
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
extern int errno;
#endif
#define IGNORE_LS_FATAL_ERROR
#include "../common/servertalk.h"
#include "LoginServer.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "WorldConfig.h"
extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numzones;
extern int32 numplayers;
extern volatile bool RunLoops;
volatile bool LoginLoopRunning = false;
bool AttemptingConnect = false;
#ifdef DUAL_SERVER
LoginServer::LoginServer(const char* iAddress, const char* iAddress2, int16 iPort, int16 iPort2)
#else
LoginServer::LoginServer(const char* iAddress, int16 iPort)
#endif
: statusupdate_timer(LoginServer_StatusUpdateInterval)
{
LoginServerIP = ResolveIP(iAddress);
LoginServerPort = iPort;
tcpc = new EmuTCPConnection(true);
tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);
#ifdef DUAL_SERVER //Angelox
LoginServerIP = ResolveIP(iAddress2);
LoginServerPort = iPort2;
tcpc2 = new EmuTCPConnection(true);
tcpc2->SetPacketMode(EmuTCPConnection::packetModeLogin);
#endif
}
LoginServer::~LoginServer() {
delete tcpc;
#ifdef DUAL_SERVER
delete tcpc2;
#endif
}
bool LoginServer::Process() {
const WorldConfig *Config=WorldConfig::get();
if (statusupdate_timer.Check()) {
this->SendStatus();
}
/************ Get all packets from packet manager out queue and process them ************/
ServerPacket *pack = 0;
#ifdef DUAL_SERVER
ServerPacket *pack2 = 0;
#endif
while((pack = tcpc->PopPacket()))
{
_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
_hex(WORLD__LS_TRACE,pack->pBuffer,pack->size);
switch(pack->opcode) {
case 0:
break;
case ServerOP_KeepAlive: {
// ignore this
break;
}
case ServerOP_UsertoWorldReq: {
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;
int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
sint16 status = database.CheckStatus(id);
ServerPacket* outpack = new ServerPacket;
outpack->opcode = ServerOP_UsertoWorldResp;
outpack->size = sizeof(UsertoWorldResponse_Struct);
outpack->pBuffer = new uchar[outpack->size];
memset(outpack->pBuffer, 0, outpack->size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
utwrs->lsaccountid = utwr->lsaccountid;
utwrs->ToID = utwr->FromID;
if(Config->Locked == true)
{
if((status == 0 || status < 100) && (status != -2 || status != -1))
utwrs->response = 0;
if(status >= 100)
utwrs->response = 1;
}
else {
utwrs->response = 1;
}
sint32 x = Config->MaxClients;
if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if(status == -1)
utwrs->response = -1;
if(status == -2)
utwrs->response = -2;
utwrs->worldid = utwr->worldid;
SendPacket(outpack);
delete outpack;
break;
}
case ServerOP_LSClientAuth: {
ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack->pBuffer;
if (RuleI(World, AccountSessionLimit) >= 0) {
// Enforce the limit on the number of characters on the same account that can be
// online at the same time.
client_list.EnforceSessionLimit(slsca->lsaccount_id);
}
client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
break;
}
case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
WorldConfig::DisableLoginserver();
_log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
_log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
if (pack->size > 1) {
_log(WORLD__LS_ERR, " %s",pack->pBuffer);
}
break;
}
case ServerOP_SystemwideMessage: {
ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack->pBuffer;
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
break;
}
case ServerOP_LSRemoteAddr: {
if (!Config->WorldAddress.length()) {
WorldConfig::SetWorldAddress((char *)pack->pBuffer);
_log(WORLD__LS, "Loginserver provided %s as world address",pack->pBuffer);
}
break;
}
default:
{
_log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size);
DumpPacket(pack->pBuffer, pack->size);
break;
}
}
delete pack;
}
#ifdef DUAL_SERVER
while((pack2 = tcpc2->PopPacket()))
{
_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack2->opcode);
_hex(WORLD__LS_TRACE,pack2->pBuffer,pack2->size);
switch(pack2->opcode) {
case 0:
break;
case ServerOP_KeepAlive: {
// ignore this
break;
}
case ServerOP_UsertoWorldReq: {
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack2->pBuffer;
int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
sint16 status = database.CheckStatus(id);
ServerPacket* outpack = new ServerPacket;
outpack->opcode = ServerOP_UsertoWorldResp;
outpack->size = sizeof(UsertoWorldResponse_Struct);
outpack->pBuffer = new uchar[outpack->size];
memset(outpack->pBuffer, 0, outpack->size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
utwrs->lsaccountid = utwr->lsaccountid;
utwrs->ToID = utwr->FromID;
if(Config->Locked == true)
{
if((status == 0 || status < 100) && (status != -2 || status != -1))
utwrs->response = 0;
if(status >= 100)
utwrs->response = 1;
}
else {
utwrs->response = 1;
}
sint32 x = Config->MaxClients;
if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if(status == -1)
utwrs->response = -1;
if(status == -2)
utwrs->response = -2;
utwrs->worldid = utwr->worldid;
SendPacket2(outpack);
delete outpack;
break;
}
case ServerOP_LSClientAuth: {
ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack2->pBuffer;
if (RuleI(World, AccountSessionLimit) >= 0) {
// Enforce the limit on the number of characters on the same account that can be
// online at the same time.
client_list.EnforceSessionLimit(slsca->lsaccount_id);
}
client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
break;
}
case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
WorldConfig::DisableLoginserver();
_log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
_log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
if (pack2->size > 1) {
_log(WORLD__LS_ERR, " %s",pack2->pBuffer);
}
break;
}
case ServerOP_SystemwideMessage: {
ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack2->pBuffer;
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
break;
}
case ServerOP_LSRemoteAddr: {
if (!Config->WorldAddress.length()) {
WorldConfig::SetWorldAddress((char *)pack2->pBuffer);
_log(WORLD__LS, "Loginserver provided %s as world address",pack2->pBuffer);
}
break;
}
default:
{
_log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack2->opcode,pack->size);
DumpPacket(pack2->pBuffer, pack2->size);
break;
}
}
delete pack2;
}
#endif //END DUAL_SERVER
return true;
}
// this should always be called in a new thread
#ifdef WIN32
void AutoInitLoginServer(void *tmp) {
#else
void *AutoInitLoginServer(void *tmp) {
#endif
srand(time(NULL));
#ifdef DUAL_SERVER
if (loginserver.ConnectReady() && loginserver.ConnectReady2()) {
#else
if (loginserver.ConnectReady()) {
#endif
InitLoginServer();
}
#ifndef WIN32
return 0;
#endif
}
//Start
bool InitLoginServer() {
#ifdef DUAL_SERVER
_log(WORLD__LS, "Dual Connecting to the login servers...");
#else
_log(WORLD__LS, "Connecting to login server...");
#endif
const WorldConfig *Config=WorldConfig::get();
#ifdef DUAL_SERVER
if ((!loginserver.ConnectReady()) || (!loginserver.ConnectReady2())) {
#else
if (!loginserver.ConnectReady()) {
#endif
_log(WORLD__LS_ERR,"InitLoginServer() while already attempting connect");
return false;
}
if (!Config->LoginHost.length()) {
_log(WORLD__LS_ERR,"Login server info not loaded");
return false;
}
AttemptingConnect = true;
#ifdef DUAL_SERVER
loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginHost2.c_str(), Config->LoginPort2);
#else
loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort);
#endif
return true;
}
#ifdef DUAL_SERVER
bool LoginServer::Connect(const char* iAddress, int16 iPort, const char* iAddress2, int16 iPort2) {
#else
bool LoginServer::Connect(const char* iAddress, int16 iPort) {
#endif
char tmp[25];
if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){
minilogin = true;
_log(WORLD__LS, "Setting World to MiniLogin Server type");
}
else
minilogin = false;
if (minilogin && WorldConfig::get()->WorldAddress.length()==0) {
_log(WORLD__LS_ERR, "**** For minilogin to work, you need to set the <address> element in the <world> section.");
return false;
}
char errbuf[TCPConnection_ErrorBufferSize];
#ifdef DUAL_SERVER
//char errbuf2[TCPConnection_ErrorBufferSize];
#endif
if (iAddress == 0) {
_log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
return false;
}
else {
if ((LoginServerIP = ResolveIP(iAddress, errbuf)) == 0) {
_log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress);
return false;
}
}
if (iPort != 0)
LoginServerPort = iPort;
if (LoginServerIP == 0 || LoginServerPort == 0) {
_log(WORLD__LS_ERR, "LoginServer::Connect: Connect info incomplete, cannot connect");
return false;
}
#ifdef DUAL_SERVER
if (iAddress2 == 0) {
_log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
return false;
}
else {
if ((LoginServerIP2 = ResolveIP(iAddress2, errbuf)) == 0) {
_log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress2);
return false;
}
}
if (iPort2 != 0)
LoginServerPort2 = iPort2;
if (LoginServerIP2 == 0 || LoginServerPort2 == 0) {
_log(WORLD__LS_ERR, "LoginServer2::Connect: Connect info incomplete, cannot connect");
return false;
}
if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf) && tcpc2->ConnectIP(LoginServerIP2, LoginServerPort2, errbuf)) {
_log(WORLD__LS, "Connected to EqEmu Loginserver: %s:%d",iAddress,LoginServerPort);
_log(WORLD__LS, "Connected to AXClassic Loginserver: %s:%d",iAddress2,LoginServerPort2);
#else
if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
_log(WORLD__LS, "Connected to Loginserver: %s:%d",iAddress,LoginServerPort);
#endif
if (minilogin)
SendInfo();
else
SendNewInfo();
SendStatus();
zoneserver_list.SendLSZones();
return true;
}
else {
#ifdef DUAL_SERVER
_log(WORLD__LS_ERR, "FATAL ERROR! - SERVERS NOT CONNECTED. One or more connections not esablished, so none are connected.",errbuf);
#else
_log(WORLD__LS_ERR, "Could not connect to login server: %s",errbuf);
#endif
return false;
}
}
void LoginServer::SendInfo() {
const WorldConfig *Config=WorldConfig::get();
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSInfo;
pack->size = sizeof(ServerLSInfo_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerLSInfo_Struct* lsi = (ServerLSInfo_Struct*) pack->pBuffer;
strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
strcpy(lsi->serverversion, CURRENT_VERSION);
strcpy(lsi->name, Config->LongName.c_str());
strcpy(lsi->account, Config->LoginAccount.c_str());
strcpy(lsi->password, Config->LoginPassword.c_str());
strcpy(lsi->address, Config->WorldAddress.c_str());
SendPacket(pack);
#ifdef DUAL_SERVER
ServerPacket* pack2 = new ServerPacket;
pack2->opcode = ServerOP_LSInfo;
pack2->size = sizeof(ServerLSInfo_Struct);
pack2->pBuffer = new uchar[pack2->size];
memset(pack2->pBuffer, 0, pack2->size);
ServerLSInfo_Struct* lsi2 = (ServerLSInfo_Struct*) pack2->pBuffer;
strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
strcpy(lsi2->serverversion, CURRENT_VERSION);
strcpy(lsi2->name, Config->LongName.c_str());
strcpy(lsi2->account, Config->LoginAccount2.c_str());
strcpy(lsi2->password, Config->LoginPassword2.c_str());
strcpy(lsi2->address, Config->WorldAddress.c_str());
SendPacket2(pack2);
#endif
delete pack;
#ifdef DUAL_SERVER
delete pack2;
#endif
}
void LoginServer::SendNewInfo() {
uint16 port;
const WorldConfig *Config=WorldConfig::get();
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_NewLSInfo;
pack->size = sizeof(ServerNewLSInfo_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerNewLSInfo_Struct* lsi = (ServerNewLSInfo_Struct*) pack->pBuffer;
strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
strcpy(lsi->serverversion, CURRENT_VERSION);
strcpy(lsi->name, Config->LongName.c_str());
strcpy(lsi->shortname, Config->ShortName.c_str());
strcpy(lsi->account, Config->LoginAccount.c_str());
strcpy(lsi->password, Config->LoginPassword.c_str());
if (Config->WorldAddress.length())
strcpy(lsi->remote_address, Config->WorldAddress.c_str());
if (Config->LocalAddress.length())
strcpy(lsi->local_address, Config->LocalAddress.c_str());
else {
tcpc->GetSockName(lsi->local_address,&port);
WorldConfig::SetLocalAddress(lsi->local_address);
}
SendPacket(pack);
#ifdef DUAL_SERVER
ServerPacket* pack2 = new ServerPacket;
pack2->opcode = ServerOP_NewLSInfo;
pack2->size = sizeof(ServerNewLSInfo_Struct);
pack2->pBuffer = new uchar[pack2->size];
memset(pack2->pBuffer, 0, pack2->size);
ServerNewLSInfo_Struct* lsi2 = (ServerNewLSInfo_Struct*) pack2->pBuffer;
strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
strcpy(lsi2->serverversion, CURRENT_VERSION);
strcpy(lsi2->name, Config->LongName.c_str());
strcpy(lsi2->shortname, Config->ShortName.c_str());
strcpy(lsi2->account, Config->LoginAccount.c_str());
strcpy(lsi2->password, Config->LoginPassword.c_str());
if (Config->WorldAddress.length())
strcpy(lsi2->remote_address, Config->WorldAddress.c_str());
if (Config->LocalAddress.length())
strcpy(lsi2->local_address, Config->LocalAddress.c_str());
else {
tcpc2->GetSockName(lsi2->local_address,&port);
WorldConfig::SetLocalAddress(lsi2->local_address);
}
//SendPacket(pack); Angelox
SendPacket2(pack2);
#endif
delete pack;
#ifdef DUAL_SERVER
delete pack2;
#endif
}
void LoginServer::SendStatus() {
statusupdate_timer.Start();
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSStatus;
pack->size = sizeof(ServerLSStatus_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerLSStatus_Struct* lss = (ServerLSStatus_Struct*) pack->pBuffer;
if (WorldConfig::get()->Locked)
lss->status = -2;
else if (numzones <= 0)
lss->status = -2;
else
lss->status = numplayers;
lss->num_zones = numzones;
lss->num_players = numplayers;
SendPacket(pack);
#ifdef DUAL_SERVER
SendPacket2(pack);
#endif
delete pack;
}
client.cpp
Code:
#include "../common/debug.h"
#include "../common/EQPacket.h"
#include "../common/EQStreamIntf.h"
#include "../common/misc.h"
#include <iostream>
using namespace std;
#include <iomanip>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include <limits.h>
//FatherNitwit: uncomment to enable my IP based authentication hack
//#define IPBASED_AUTH_HACK
// Disgrace: for windows compile
#ifdef WIN32
#include <windows.h>
#include <winsock.h>
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "client.h"
#include "../common/emu_opcodes.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "../common/EQStreamIntf.h"
#include "worlddb.h"
#include "../common/Item.h"
#include "../common/races.h"
#include "../common/classes.h"
#include "../common/languages.h"
#include "../common/skills.h"
#include "../common/extprofile.h"
#include "WorldConfig.h"
#include "LoginServer.h"
#include "zoneserver.h"
#include "zonelist.h"
#include "clientlist.h"
#include "wguild_mgr.h"
#include "../common/rulesys.h"
#include "SoFCharCreateData.h"
extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numclients;
extern volatile bool RunLoops;
Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
CLE_keepalive_timer(RuleI(World, ClientKeepaliveTimeoutMS)),
connect(1000),
eqs(ieqs)
{
// Live does not send datarate as of 3/11/2005
//eqs->SetDataRate(7);
ip = eqs->GetRemoteIP();
port = ntohs(eqs->GetRemotePort());
autobootup_timeout.Disable();
connect.Disable();
seencharsel = false;
cle = 0;
zoneID = 0;
char_name[0] = 0;
charid = 0;
pwaitingforbootup = 0;
StartInTutorial = false;
SoFClient = false;
numclients++;
}
Client::~Client() {
if (RunLoops && cle && zoneID == 0)
cle->SetOnline(CLE_Status_Offline);
numclients--;
//let the stream factory know were done with this stream
eqs->Close();
eqs->ReleaseFromUse();
}
void Client::SendLogServer()
{
EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogServer, sizeof(LogServer_Struct));
LogServer_Struct *l=(LogServer_Struct *)outapp->pBuffer;
const char *wsn=WorldConfig::get()->ShortName.c_str();
memcpy(l->worldshortname,wsn,strlen(wsn));
if(RuleB(Mail, EnableMailSystem))
l->enablemail = 1;
if(RuleB(Chat, EnableVoiceMacros))
l->enablevoicemacros = 1;
if(database.GetServerType() == 1)
l->enable_pvp = 1;
//enable when we are ready to implement this!
//l->enable_petition_wnd = 1;
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendEnterWorld(string name)
{
char char_name[32]= { 0 };
if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) {
if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
eqs->Close();
return;
} else {
clog(WORLD__CLIENT,"Telling client to continue session.");
}
}
EQApplicationPacket *outapp = new EQApplicationPacket(OP_EnterWorld, strlen(char_name)+1);
memcpy(outapp->pBuffer,char_name,strlen(char_name)+1);
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendExpansionInfo() {
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
char val[20] = {0};
if (database.GetVariable("Expansions", val, 20)) {
eis->Expansions = atoi(val);
}
else {
eis->Expansions = 0x1FF;
}
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendCharInfo() {
if (cle) {
cle->SetOnline(CLE_Status_CharSelect);
}
seencharsel = true;
// Send OP_SendCharInfo
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;
database.GetCharSelectInfo(GetAccountID(), cs);
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendPostEnterWorld() {
EQApplicationPacket *outapp = new EQApplicationPacket(OP_PostEnterWorld, 1);
outapp->size=0;
QueuePacket(outapp);
safe_delete(outapp);
}
bool Client::HandlePacket(const EQApplicationPacket *app) {
const WorldConfig *Config=WorldConfig::get();
EmuOpcode opcode = app->GetOpcode();
clog(WORLD__CLIENT_TRACE,"Recevied EQApplicationPacket");
_pkt(WORLD__CLIENT_TRACE,app);
bool ret = true;
if (!eqs->CheckState(ESTABLISHED)) {
clog(WORLD__CLIENT,"Client disconnected (net inactive on send)");
return false;
}
// Voidd: Anti-GM Account hack, Checks source ip against valid GM Account IP Addresses
if (RuleB(World, GMAccountIPList) && this->GetAdmin() >= (RuleI(World, MinGMAntiHackStatus))) {
if(!database.CheckGMIPs(long2ip(this->GetIP()).c_str(), this->GetAccountID())) {
clog(WORLD__CLIENT,"GM Account not permited from source address %s and accountid %i", long2ip(this->GetIP()).c_str(), this->GetAccountID());
eqs->Close();
}
}
if (GetAccountID() == 0 && opcode != OP_SendLoginInfo) {
// Got a packet other than OP_SendLoginInfo when not logged in
clog(WORLD__CLIENT_ERR,"Expecting OP_SendLoginInfo, got %s", OpcodeNames[opcode]);
return false;
}
else if (opcode == OP_AckPacket) {
return true;
}
switch(opcode)
{
case OP_CrashDump:
break;
case OP_SendLoginInfo:
{
if (app->size != sizeof(LoginInfo_Struct)) {
ret = false;
break;
}
string StreamDescription = eqs->Describe();
if(StreamDescription == "Patch SoF")
SoFClient = true;
LoginInfo_Struct *li=(LoginInfo_Struct *)app->pBuffer;
// Quagmire - max len for name is 18, pass 15
char name[19] = {0};
char password[16] = {0};
strncpy(name, (char*)li->login_info,18);
strncpy(password, (char*)&(li->login_info[strlen(name)+1]), 15);
if (strlen(password) <= 1) {
// TODO: Find out how to tell the client wrong username/password
clog(WORLD__CLIENT_ERR,"Login without a password");
ret = false;
break;
}
pZoning=(li->zoning==1);
#ifdef IPBASED_AUTH_HACK
struct in_addr tmpip;
tmpip.s_addr = ip;
#endif
int32 id=0;
bool minilogin = loginserver.MiniLogin();
if(minilogin){
struct in_addr miniip;
miniip.s_addr = ip;
id = database.GetMiniLoginAccount(inet_ntoa(miniip));
}
else if(strncasecmp(name, "LS#", 3) == 0)
id=atoi(&name[3]);
else
id=atoi(name);
#ifdef IPBASED_AUTH_HACK
if ((cle = zoneserver_list.CheckAuth(inet_ntoa(tmpip), password)))
#else
#ifdef DUAL_SERVER
if (loginserver.Connected() == false && !pZoning) {
clog(WORLD__CLIENT_ERR,"Error: You're disconnected from one login server, you need to re-connect.");
}
#else
if (loginserver.Connected() == false && !pZoning) {
clog(WORLD__CLIENT_ERR,"Error: Login server login while not connected to login server.");
ret = false;
break;
}
#endif
if ((minilogin && (cle = client_list.CheckAuth(id,password,ip))) || (cle = client_list.CheckAuth(id, password)))
#endif
{
if (cle->AccountID() == 0 || (!minilogin && cle->LSID()==0)) {
clog(WORLD__CLIENT_ERR,"ID is 0. Is this server connected to minilogin?");
if(!minilogin)
clog(WORLD__CLIENT_ERR,"If so you forget the minilogin variable...");
else
clog(WORLD__CLIENT_ERR,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table.");
ret = false;
break;
}
cle->SetOnline();
clog(WORLD__CLIENT,"Logged in. Mode=%s",pZoning ? "(Zoning)" : "(CharSel)");
if(minilogin){
WorldConfig::DisableStats();
clog(WORLD__CLIENT,"MiniLogin Account #%d",cle->AccountID());
}
else {
clog(WORLD__CLIENT,"LS Account #%d",cle->LSID());
}
if(Config->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSPlayerJoinWorld;
pack->size = sizeof(ServerLSPlayerJoinWorld_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer,0,pack->size);
ServerLSPlayerJoinWorld_Struct* join =(ServerLSPlayerJoinWorld_Struct*)pack->pBuffer;
strcpy(join->key,GetLSKey());
join->lsaccount_id = GetLSID();
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
if (!pZoning)
SendGuildList();
SendLogServer();
SendApproveWorld();
SendEnterWorld(cle->name());
SendPostEnterWorld();
if (!pZoning) {
SendExpansionInfo();
SendCharInfo();
database.LoginIP(cle->AccountID(), long2ip(GetIP()).c_str());
}
}
else {
// TODO: Find out how to tell the client wrong username/password
clog(WORLD__CLIENT_ERR,"Bad/Expired session key '%s'",name);
ret = false;
break;
}
if (!cle)
break;
cle->SetIP(GetIP());
break;
}
case OP_ApproveName: //Name approval
{
if (GetAccountID() == 0) {
clog(WORLD__CLIENT_ERR,"Name approval request with no logged in account");
ret = false;
break;
}
snprintf(char_name, 64, "%s", (char*)app->pBuffer);
uchar race = app->pBuffer[64];
uchar clas = app->pBuffer[68];
clog(WORLD__CLIENT,"Name approval request. Name=%s, race=%s, class=%s",char_name,GetRaceName(race),GetEQClassName(clas));
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket;
outapp->SetOpcode(OP_ApproveName);
outapp->pBuffer = new uchar[1];
outapp->size = 1;
bool valid;
if(!database.CheckNameFilter(char_name)) {
valid = false;
}
else if(char_name[0] < 'A' && char_name[0] > 'Z') {
//name must begin with an upper-case letter.
valid = false;
}
else if (database.ReserveName(GetAccountID(), char_name)) {
valid = true;
}
else {
valid = false;
}
outapp->pBuffer[0] = valid? 1 : 0;
QueuePacket(outapp);
safe_delete(outapp);
break;
}
case OP_RandomNameGenerator:
{
// creates up to a 10 char name
char vowels[18]="aeiouyaeiouaeioe";
char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd";
char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr";
int rndnum=rand()%76,n=1;
bool dlc=false;
bool vwl=false;
bool dbl=false;
if (rndnum>63)
{ // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk"
rndname[0]=paircons[rndnum];
rndname[1]=paircons[rndnum+1];
n=2;
}
else if (rndnum>16)
{
rndnum-=17;
rndname[0]=cons[rndnum];
}
else
{
rndname[0]=vowels[rndnum];
vwl=true;
}
int namlen=(rand()%6)+5;
for (int i=n;i<namlen;i++)
{
dlc=false;
if (vwl) //last char was a vowel
{ // so pick a cons or cons pair
rndnum=rand()%63;
if (rndnum>46)
{ // pick a cons pair
if (i>namlen-3) // last 2 chars in name?
{ // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
rndnum=(rand()%8)*2;
}
else
{ // pick any from the set
rndnum=(rndnum-47)*2;
}
rndname[i]=paircons[rndnum];
rndname[i+1]=paircons[rndnum+1];
dlc=true; // flag keeps second letter from being doubled below
i+=1;
}
else
{ // select a single cons
rndname[i]=cons[rndnum];
}
}
else
{ // select a vowel
rndname[i]=vowels[rand()%17];
}
vwl=!vwl;
if (!dbl && !dlc)
{ // one chance at double letters in name
if (!(rand()%(i+10))) // chances decrease towards end of name
{
rndname[i+1]=rndname[i];
dbl=true;
i+=1;
}
}
}
rndname[0]=toupper(rndname[0]);
NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
memset(ngs->name,0,64);
strcpy(ngs->name,rndname);
// char names[8][64] = { "How", "About", "You", "Think", "Of", "Your", "Own", "Name" };
// //Could have parts of the random name in this struct and they compile together
// NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
// strncpy(ngs->name,"Notcreated",64);
QueuePacket(app);
break;
}
case OP_CharacterCreateRequest: {
// New OpCode in SoF
//
SoFClient = true;
EQApplicationPacket *outapp = new EQApplicationPacket(OP_CharacterCreateRequest, sizeof(SoFCharCreateInfo));
memcpy(outapp->pBuffer, &SoFCharCreateInfo, sizeof(SoFCharCreateInfo));
QueuePacket(outapp);
safe_delete(outapp);
break;
}
case OP_CharacterCreate: //Char create
{
if (GetAccountID() == 0)
{
clog(WORLD__CLIENT_ERR,"Account ID not set; unable to create character.");
ret = false;
break;
}
else if (app->size != sizeof(CharCreate_Struct))
{
clog(WORLD__CLIENT_ERR,"Wrong size on OP_CharacterCreate. Got: %d, Expected: %d",app->size,sizeof(CharCreate_Struct));
DumpPacket(app);
break;
}
CharCreate_Struct *cc = (CharCreate_Struct*)app->pBuffer;
if(OPCharCreate(char_name,cc) == false)
{
database.DeleteCharacter(char_name);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ApproveName, 1);
outapp->pBuffer[0] = 0;
QueuePacket(outapp);
safe_delete(outapp);
}
else
StartInTutorial = true;
SendCharInfo();
break;
}
case OP_EnterWorld: // Enter world
{
if (GetAccountID() == 0) {
clog(WORLD__CLIENT_ERR,"Enter world with no logged in account");
eqs->Close();
break;
}
if(GetAdmin() < 0)
{
clog(WORLD__CLIENT,"Account banned or suspended.");
eqs->Close();
break;
}
if (RuleI(World, MaxClientsPerIP) >= 0) {
client_list.GetCLEIP(this->GetIP()); //Lieka Edit Begin: Check current CLE Entry IPs against incoming connection
}
EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer;
strncpy(char_name, ew->name, 64);
EQApplicationPacket *outapp;
int32 tmpaccid = 0;
charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID);
if (charid == 0 || tmpaccid != GetAccountID()) {
clog(WORLD__CLIENT_ERR,"Could not get CharInfo for '%s'",char_name);
eqs->Close();
break;
}
// Make sure this account owns this character
if (tmpaccid != GetAccountID()) {
clog(WORLD__CLIENT_ERR,"This account does not own the character named '%s'",char_name);
eqs->Close();
break;
}
if(!pZoning && ew->return_home)
{
CharacterSelect_Struct* cs = new CharacterSelect_Struct;
memset(cs, 0, sizeof(CharacterSelect_Struct));
database.GetCharSelectInfo(GetAccountID(), cs);
bool home_enabled = false;
for(int x = 0; x < 10; ++x)
{
if(strcasecmp(cs->name[x], char_name) == 0)
{
if(cs->gohome[x] == 1)
{
home_enabled = true;
break;
}
}
}
safe_delete(cs);
if(home_enabled)
{
zoneID = database.MoveCharacterToBind(charid,4);
}
else
{
clog(WORLD__CLIENT_ERR,"'%s' is trying to go home before they're able...",char_name);
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to enter the tutorial without having go home enabled for this character.");
eqs->Close();
break;
}
}
/*
if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
CharacterSelect_Struct* cs = new CharacterSelect_Struct;
memset(cs, 0, sizeof(CharacterSelect_Struct));
database.GetCharSelectInfo(GetAccountID(), cs);
bool tutorial_enabled = false;
for(int x = 0; x < 10; ++x)
{
if(strcasecmp(cs->name[x], char_name) == 0)
{
if(cs->tutorial[x] == 1)
{
tutorial_enabled = true;
break;
}
}
}
safe_delete(cs);
if(tutorial_enabled)
{
zoneID = RuleI(World, TutorialZoneID);
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
}
else
{
clog(WORLD__CLIENT_ERR,"'%s' is trying to go to tutorial but are not allowed...",char_name);
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
eqs->Close();
break;
}
// HACK: Entering the Tutorial directly from Character Creation (without going back to Char Select)
// does not work correctly yet in SoF, so bounce them back to Character Select first.
//
if(SoFClient && StartInTutorial) {
ZoneUnavail();
StartInTutorial = false;
break;
}
}
*/
if (zoneID == 0 || !database.GetZoneName(zoneID)) {
// This is to save people in an invalid zone, once it's removed from the DB
database.MoveCharacterToZone(charid, "arena");
clog(WORLD__CLIENT_ERR, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name);
}
if(instanceID > 0)
{
if(!database.VerifyInstanceAlive(instanceID, GetCharID()))
{
zoneID = database.MoveCharacterToBind(charid);
instanceID = 0;
}
else
{
if(!database.VerifyZoneInstance(zoneID, instanceID))
{
zoneID = database.MoveCharacterToBind(charid);
instanceID = 0;
}
}
}
if(!pZoning) {
database.SetGroupID(char_name, 0, charid);
database.SetLFP(charid, false);
database.SetLFG(charid, false);
}
else{
int32 groupid=database.GetGroupID(char_name);
if(groupid>0){
char* leader=0;
char leaderbuf[64]={0};
if((leader=database.GetGroupLeaderForLogin(char_name,leaderbuf)) && strlen(leader)>1){
EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct));
GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer;
gj->action=8;
strcpy(gj->yourname,char_name);
strcpy(gj->membername,leader);
QueuePacket(outapp3);
safe_delete(outapp3);
}
}
}
//Angelox
outapp = new EQApplicationPacket(OP_MOTD);
#ifdef DUAL_SERVER
char tmp[500] = {0};
if ((database.GetVariable("MOTD", tmp, 500)) && (GetLSID() > 4999999)) {
outapp->size = strlen(tmp)+1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer,0,outapp->size);
strcpy((char*)outapp->pBuffer, tmp);
}
else if ((database.GetVariable("MOTDEqEmu", tmp, 500)) && (GetLSID() < 5000000)) {
outapp->size = strlen(tmp)+1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer,0,outapp->size);
strcpy((char*)outapp->pBuffer, tmp);
}
#else
char tmp[500] = {0};
if (database.GetVariable("MOTD", tmp, 500)) {
outapp->size = strlen(tmp)+1;
outapp->pBuffer = new uchar[outapp->size];
memset(outapp->pBuffer,0,outapp->size);
strcpy((char*)outapp->pBuffer, tmp);
}
#endif
else {
// Null Message of the Day. :)
outapp->size = 1;
outapp->pBuffer = new uchar[outapp->size];
outapp->pBuffer[0] = 0;
}
QueuePacket(outapp);
safe_delete(outapp);
int MailKey = MakeRandomInt(1, INT_MAX);
database.SetMailKey(charid, GetIP(), MailKey);
char ConnectionType = (SoFClient ? 'S' : 'C');
EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_SetChatServer);
char buffer[112];
sprintf(buffer,"%s,%i,%s.%s,%c%08X",
Config->ChatHost.c_str(),
Config->ChatPort,
Config->ShortName.c_str(),
this->GetCharName(), ConnectionType, MailKey
);
outapp2->size=strlen(buffer)+1;
outapp2->pBuffer = new uchar[outapp2->size];
memcpy(outapp2->pBuffer,buffer,outapp2->size);
QueuePacket(outapp2);
safe_delete(outapp2);
outapp2 = new EQApplicationPacket(OP_SetChatServer2);
if(!SoFClient)
ConnectionType = 'M';
sprintf(buffer,"%s,%i,%s.%s,%c%08X",
Config->MailHost.c_str(),
Config->MailPort,
Config->ShortName.c_str(),
this->GetCharName(), ConnectionType, MailKey
);
outapp2->size=strlen(buffer)+1;
outapp2->pBuffer = new uchar[outapp2->size];
memcpy(outapp2->pBuffer,buffer,outapp2->size);
QueuePacket(outapp2);
safe_delete(outapp2);
EnterWorld();
break;
}
case OP_LoginComplete:{
break;
}
case OP_DeleteCharacter: {
int32 char_acct_id = database.GetAccountIDByChar((char*)app->pBuffer);
if(char_acct_id == GetAccountID())
{
clog(WORLD__CLIENT,"Delete character: %s",app->pBuffer);
database.DeleteCharacter((char *)app->pBuffer);
SendCharInfo();
}
break;
}
case OP_ApproveWorld:
{
break;
}
case OP_WorldClientReady:{
break;
}
case OP_World_Client_CRC1:
case OP_World_Client_CRC2: {
// Derision: There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
// then 'Start Tutorial' was not chosen.
StartInTutorial = false;
break;
}
case OP_WearChange: { // User has selected a different character
break;
}
case OP_WorldComplete: {
eqs->Close();
break;
}
case OP_LoginUnknown1:
case OP_LoginUnknown2:
break;
default: {
clog(WORLD__CLIENT_ERR,"Received unknown EQApplicationPacket");
_pkt(WORLD__CLIENT_ERR,app);
break;
}
}
return ret;
}
bool Client::Process() {
bool ret = true;
//bool sendguilds = true;
sockaddr_in to;
memset((char *) &to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = port;
to.sin_addr.s_addr = ip;
if (autobootup_timeout.Check()) {
clog(WORLD__CLIENT_ERR, "Zone bootup timer expired, bootup failed or too slow.");
ZoneUnavail();
}
if(connect.Check()){
SendGuildList();// Send OPCode: OP_GuildsList
SendApproveWorld();
connect.Disable();
}
if (CLE_keepalive_timer.Check()) {
if (cle)
cle->KeepAlive();
}
/************ Get all packets from packet manager out queue and process them ************/
EQApplicationPacket *app = 0;
while(ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
ret = HandlePacket(app);
delete app;
}
if (!eqs->CheckState(ESTABLISHED)) {
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSPlayerLeftWorld;
pack->size = sizeof(ServerLSPlayerLeftWorld_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer,0,pack->size);
ServerLSPlayerLeftWorld_Struct* logout =(ServerLSPlayerLeftWorld_Struct*)pack->pBuffer;
strcpy(logout->key,GetLSKey());
logout->lsaccount_id = GetLSID();
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
clog(WORLD__CLIENT,"Client disconnected (not active in process)");
return false;
}
return ret;
}
void Client::EnterWorld(bool TryBootup) {
if (zoneID == 0)
return;
ZoneServer* zs = NULL;
if(instanceID > 0)
{
if(database.VerifyInstanceAlive(instanceID, GetCharID()))
{
if(database.VerifyZoneInstance(zoneID, instanceID))
{
zs = zoneserver_list.FindByInstanceID(instanceID);
}
else
{
instanceID = 0;
zs = NULL;
database.MoveCharacterToBind(GetCharID());
ZoneUnavail();
return;
}
}
else
{
instanceID = 0;
zs = NULL;
database.MoveCharacterToBind(GetCharID());
ZoneUnavail();
return;
}
}
else
zs = zoneserver_list.FindByZoneID(zoneID);
const char *zone_name=database.GetZoneName(zoneID, true);
if (zs) {
// warn the world we're comming, so it knows not to shutdown
zs->IncommingClient(this);
}
else {
if (TryBootup) {
clog(WORLD__CLIENT,"Attempting autobootup of %s (%d:%d)",zone_name,zoneID,instanceID);
autobootup_timeout.Start();
pwaitingforbootup = zoneserver_list.TriggerBootup(zoneID, instanceID);
if (pwaitingforbootup == 0) {
clog(WORLD__CLIENT_ERR,"No zoneserver available to boot up.");
ZoneUnavail();
}
return;
}
else {
clog(WORLD__CLIENT_ERR,"Requested zone %s is no running.",zone_name);
ZoneUnavail();
return;
}
}
pwaitingforbootup = 0;
cle->SetChar(charid, char_name);
database.UpdateLiveChar(char_name, GetAccountID());
clog(WORLD__CLIENT,"%s %s (%d:%d)",seencharsel ? "Entering zone" : "Zoning to",zone_name,zoneID,instanceID);
// database.SetAuthentication(account_id, char_name, zone_name, ip);
if (seencharsel) {
if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zoneID)) {
clog(WORLD__CLIENT_ERR,"Enter world failed. Zone is locked.");
ZoneUnavail();
return;
}
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_AcceptWorldEntrance;
pack->size = sizeof(WorldToZone_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
wtz->account_id = GetAccountID();
wtz->response = 0;
zs->SendPacket(pack);
delete pack;
}
else { // if they havent seen character select screen, we can assume this is a zone
// to zone movement, which should be preauthorized before they leave the previous zone
Clearance(1);
}
}
void Client::Clearance(sint8 response)
{
ZoneServer* zs = NULL;
if(instanceID > 0)
{
zs = zoneserver_list.FindByInstanceID(instanceID);
}
else
{
zs = zoneserver_list.FindByZoneID(zoneID);
}
if(zs == 0 || response == -1 || response == 0)
{
if (zs == 0)
{
clog(WORLD__CLIENT_ERR,"Unable to find zoneserver in Client::Clearance!!");
} else {
clog(WORLD__CLIENT_ERR, "Invalid response %d in Client::Clearance", response);
}
ZoneUnavail();
return;
}
EQApplicationPacket* outapp;
if (zs->GetCAddress() == NULL) {
clog(WORLD__CLIENT_ERR, "Unable to do zs->GetCAddress() in Client::Clearance!!");
ZoneUnavail();
return;
}
if (zoneID == 0) {
clog(WORLD__CLIENT_ERR, "zoneID is NULL in Client::Clearance!!");
ZoneUnavail();
return;
}
const char* zonename = database.GetZoneName(zoneID);
if (zonename == 0) {
clog(WORLD__CLIENT_ERR, "zonename is NULL in Client::Clearance!!");
ZoneUnavail();
return;
}
// @bp This is the chat server
/*
char packetData[] = "64.37.148.34.9876,MyServer,Testchar,23cd2c95";
outapp = new EQApplicationPacket(OP_0x0282, sizeof(packetData));
strcpy((char*)outapp->pBuffer, packetData);
QueuePacket(outapp);
delete outapp;
*/
// Send zone server IP data
outapp = new EQApplicationPacket(OP_ZoneServerInfo, sizeof(ZoneServerInfo_Struct));
ZoneServerInfo_Struct* zsi = (ZoneServerInfo_Struct*)outapp->pBuffer;
const char *zs_addr=zs->GetCAddress();
if (!zs_addr[0]) {
if (cle->IsLocalClient()) {
struct in_addr in;
in.s_addr = zs->GetIP();
zs_addr=inet_ntoa(in);
if (!strcmp(zs_addr,"127.0.0.1"))
zs_addr=WorldConfig::get()->LocalAddress.c_str();
} else {
zs_addr=WorldConfig::get()->WorldAddress.c_str();
}
}
strcpy(zsi->ip, zs_addr);
zsi->port =zs->GetCPort();
clog(WORLD__CLIENT,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zoneID,instanceID,zsi->ip,zsi->port);
QueuePacket(outapp);
safe_delete(outapp);
if (cle)
cle->SetOnline(CLE_Status_Zoning);
}
void Client::ZoneUnavail() {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneUnavail, sizeof(ZoneUnavail_Struct));
ZoneUnavail_Struct* ua = (ZoneUnavail_Struct*)outapp->pBuffer;
const char* zonename = database.GetZoneName(zoneID);
if (zonename)
strcpy(ua->zonename, zonename);
QueuePacket(outapp);
delete outapp;
zoneID = 0;
pwaitingforbootup = 0;
autobootup_timeout.Disable();
}
bool Client::GenPassKey(char* key) {
char* passKey=NULL;
*passKey += ((char)('A'+((int)(rand()%26))));
*passKey += ((char)('A'+((int)(rand()%26))));
memcpy(key, passKey, strlen(passKey));
return true;
}
void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req) {
clog(WORLD__CLIENT_TRACE, "Sending EQApplicationPacket OpCode 0x%04x",app->GetOpcode());
_pkt(WORLD__CLIENT_TRACE, app);
ack_req = true; // It's broke right now, dont delete this line till fix it. =P
eqs->QueuePacket(app, ack_req);
}
void Client::SendGuildList() {
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket(OP_GuildsList);
//ask the guild manager to build us a nice guild list packet
outapp->pBuffer = guild_mgr.MakeGuildList("", outapp->size);
if(outapp->pBuffer == NULL) {
clog(GUILDS__ERROR, "Unable to make guild list!");
return;
}
clog(GUILDS__OUT_PACKETS, "Sending OP_GuildsList of length %d", outapp->size);
// _pkt(GUILDS__OUT_PACKET_TRACE, outapp);
eqs->FastQueuePacket((EQApplicationPacket **)&outapp);
}
// @merth: I have no idea what this struct is for, so it's hardcoded for now
void Client::SendApproveWorld()
{
EQApplicationPacket* outapp;
// Send OPCode: OP_ApproveWorld, size: 544
outapp = new EQApplicationPacket(OP_ApproveWorld, sizeof(ApproveWorld_Struct));
ApproveWorld_Struct* aw = (ApproveWorld_Struct*)outapp->pBuffer;
uchar foo[] = {
//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x5E,0x30,0xA5,0xCA,0xD4,0xEA,0xF5,
//0xCB,0x14,0xFC,0xF7,0x78,0xE2,0x73,0x15,0x90,0x17,0xCE,0x7A,0xEB,0xEC,0x3C,0x34,
//0x5C,0x6D,0x10,0x05,0xFC,0xEA,0xED,0x19,0xC5,0x0D,0x7A,0x82,0x17,0xCC,0xCC,0x71,
//0x56,0x38,0xDF,0x78,0x8D,0xE6,0x44,0xD3,0x6F,0xDB,0xE3,0xCF,0x21,0x30,0x75,0x2F,
//0xCD,0xDC,0xE9,0xB4,0xA4,0x4E,0x58,0xDE,0xEE,0x54,0xDD,0x87,0xDA,0xE9,0xC6,0xC8,
//0x02,0xDD,0xC4,0xFD,0x94,0x36,0x32,0xAD,0x1B,0x39,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x87,0x13,0xbe,0xc8,0xa7,0x77,0xcb,
0x27,0xed,0xe1,0xe6,0x5d,0x1c,0xaa,0xd3,0x3c,0x26,0x3b,0x6d,0x8c,0xdb,0x36,0x8d,
0x91,0x72,0xf5,0xbb,0xe0,0x5c,0x50,0x6f,0x09,0x6d,0xc9,0x1e,0xe7,0x2e,0xf4,0x38,
0x1b,0x5e,0xa8,0xc2,0xfe,0xb4,0x18,0x4a,0xf7,0x72,0x85,0x13,0xf5,0x63,0x6c,0x16,
0x69,0xf4,0xe0,0x17,0xff,0x87,0x11,0xf3,0x2b,0xb7,0x73,0x04,0x37,0xca,0xd5,0x77,
0xf8,0x03,0x20,0x0a,0x56,0x8b,0xfb,0x35,0xff,0x59,0x00,0x00,0x00,0x00,0x00,0x00,
//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x42,0x69,0x2a,0x87,0xdd,0x04,0x3d,
//0x7f,0xb1,0xb3,0xbb,0xde,0xd5,0x5f,0xfc,0x1f,0xb3,0x25,0x94,0x16,0xd5,0xf3,0x97,
//0x43,0xdf,0xb9,0x69,0x68,0xdf,0x2b,0x64,0x98,0xf5,0x44,0xbe,0x38,0x65,0xef,0xff,
//0x36,0x89,0x90,0xcf,0x26,0xbb,0x9f,0x76,0xd5,0xaf,0x6d,0xf2,0x08,0xbe,0xce,0xd8,
//0x3e,0x4b,0x53,0x8a,0xf3,0x44,0x7c,0x19,0x49,0x5d,0x97,0x99,0xd8,0x8b,0xee,0x10,
//0x1a,0x7d,0xb7,0x8b,0x49,0x9b,0x40,0x8c,0xea,0x49,0x09,0x00,0x00,0x00,0x00,0x00,
//
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00
};
memcpy(aw->unknown544, foo, sizeof(foo));
QueuePacket(outapp);
safe_delete(outapp);
}
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
{
PlayerProfile_Struct pp;
ExtendedProfile_Struct ext;
Inventory inv;
time_t bday = time(NULL);
char startzone[50]={0};
uint32 i;
struct in_addr in;
int stats_sum = cc->STR + cc->STA + cc->AGI + cc->DEX +
cc->WIS + cc->INT + cc->CHA;
in.s_addr = GetIP();
clog(WORLD__CLIENT,"Character creation request from %s LS#%d (%s:%d) : ", GetCLE()->LSName(), GetCLE()->LSID(), inet_ntoa(in), GetPort());
clog(WORLD__CLIENT,"Name: %s", name);
clog(WORLD__CLIENT,"Race: %d Class: %d Gender: %d Deity: %d Start zone: %d",
cc->race, cc->class_, cc->gender, cc->deity, cc->start_zone);
clog(WORLD__CLIENT,"STR STA AGI DEX WIS INT CHA Total");
clog(WORLD__CLIENT,"%3d %3d %3d %3d %3d %3d %3d %3d",
cc->STR, cc->STA, cc->AGI, cc->DEX, cc->WIS, cc->INT, cc->CHA,
stats_sum);
clog(WORLD__CLIENT,"Face: %d Eye colors: %d %d", cc->face, cc->eyecolor1, cc->eyecolor2);
clog(WORLD__CLIENT,"Hairstyle: %d Haircolor: %d", cc->hairstyle, cc->haircolor);
clog(WORLD__CLIENT,"Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor);
// validate the char creation struct
if(!CheckCharCreateInfo(cc))
{
clog(WORLD__CLIENT_ERR,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
return false;
}
// Convert incoming cc_s to the new PlayerProfile_Struct
memset(&pp, 0, sizeof(PlayerProfile_Struct)); // start building the profile
InitExtendedProfile(&ext);
strncpy(pp.name, name, 63);
// clean the capitalization of the name
#if 0 // on second thought, don't - this will just make the creation fail
// because the name won't match what was already reserved earlier
for (i = 0; pp.name[i] && i < 63; i++)
{
if(!isalpha(pp.name[i]))
return false;
pp.name[i] = tolower(pp.name[i]);
}
pp.name[0] = toupper(pp.name[0]);
#endif
pp.race = cc->race;
pp.class_ = cc->class_;
pp.gender = cc->gender;
pp.deity = cc->deity;
pp.STR = cc->STR;
pp.STA = cc->STA;
pp.AGI = cc->AGI;
pp.DEX = cc->DEX;
pp.WIS = cc->WIS;
pp.INT = cc->INT;
pp.CHA = cc->CHA;
pp.face = cc->face;
pp.eyecolor1 = cc->eyecolor1;
pp.eyecolor2 = cc->eyecolor2;
pp.hairstyle = cc->hairstyle;
pp.haircolor = cc->haircolor;
pp.beard = cc->beard;
pp.beardcolor = cc->beardcolor;
pp.drakkin_heritage = cc->drakkin_heritage;
pp.drakkin_tattoo = cc->drakkin_tattoo;
pp.drakkin_details = cc->drakkin_details;
pp.birthday = bday;
pp.lastlogin = bday;
pp.level = 1;
pp.points = 5;
pp.cur_hp = 1000; // 1k hp during dev only
//what was the point of this? zone dosent handle this:
//pp.expAA = 0xFFFFFFFF;
pp.hunger_level = 6000;
pp.thirst_level = 6000;
// FIXME: FV roleplay, database goodness...
// Racial Languages
SetRacialLanguages( &pp ); // bUsh
SetRaceStartingSkills( &pp ); // bUsh
SetClassStartingSkills( &pp ); // bUsh
pp.skills[SENSE_HEADING] = 200;
// Some one fucking fix this to use a field name. -Doodman
//pp.unknown3596[28] = 15; // @bp: This is to enable disc usage
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
for(i = 0; i < MAX_PP_SPELLBOOK; i++)
pp.spell_book[i] = 0xFFFFFFFF;
for(i = 0; i < MAX_PP_MEMSPELL; i++)
pp.mem_spells[i] = 0xFFFFFFFF;
for(i = 0; i < BUFF_COUNT; i++)
pp.buffs[i].spellid = 0xFFFF;
//was memset(pp.unknown3704, 0xffffffff, 8);
//but I dont think thats what you really wanted to do...
//memset is byte based
//If server is PVP by default, make all character set to it.
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
//If it is an SoF Client and the SoF Start Zone rule is set, send new chars there
if(SoFClient && (RuleI(World, SoFStartZoneID) > 0)) {
clog(WORLD__CLIENT,"Found 'SoFStartZoneID' rule setting: %i", (RuleI(World, SoFStartZoneID)));
pp.zone_id = (RuleI(World, SoFStartZoneID));
if(pp.zone_id)
database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
else
clog(WORLD__CLIENT_ERR,"Error getting zone id for Zone ID %i", (RuleI(World, SoFStartZoneID)));
}
else
{
// if there's a startzone variable put them in there
if(database.GetVariable("startzone", startzone, 50))
{
clog(WORLD__CLIENT,"Found 'startzone' variable setting: %s", startzone);
pp.zone_id = database.GetZoneID(startzone);
if(pp.zone_id)
database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
else
clog(WORLD__CLIENT_ERR,"Error getting zone id for '%s'", startzone);
}
else // otherwise use normal starting zone logic
{
if(!SoFClient)
database.GetStartZone(&pp, cc);
else
database.GetStartZoneSoF(&pp, cc);
}
}
if(!pp.zone_id)
{
pp.zone_id = 1; // qeynos
pp.x = pp.y = pp.z = -1;
}
if(!pp.binds[0].zoneId)
{
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
}
// set starting city location to the initial bind point
pp.binds[4] = pp.binds[0];
clog(WORLD__CLIENT,"Current location: %s %0.2f, %0.2f, %0.2f",
database.GetZoneName(pp.zone_id), pp.x, pp.y, pp.z);
clog(WORLD__CLIENT,"Bind location: %s %0.2f, %0.2f, %0.2f",
database.GetZoneName(pp.binds[0].zoneId), pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);
// Starting Items inventory
database.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
// now we give the pp and the inv we made to StoreCharacter
// to see if we can store it
if (!database.StoreCharacter(GetAccountID(), &pp, &inv, &ext))
{
clog(WORLD__CLIENT_ERR,"Character creation failed: %s", pp.name);
return false;
}
else
{
clog(WORLD__CLIENT,"Character creation successful: %s", pp.name);
return true;
}
}
// returns true if the request is ok, false if there's an error
bool CheckCharCreateInfo(CharCreate_Struct *cc)
{
int32 bSTR, bSTA, bAGI, bDEX, bWIS, bINT, bCHA, bTOTAL, cTOTAL, stat_points; //these are all int32 in CharCreate_Struct, so we'll make them int32 here to make the compiler shut up
int classtemp, racetemp;
int Charerrors = 0;
// solar: if this is increased you'll have to add a column to the classrace
// table below
#define _TABLE_RACES 16
static const int BaseRace[_TABLE_RACES][7] =
{ /* STR STA AGI DEX WIS INT CHR */
{ /*Human*/ 75, 75, 75, 75, 75, 75, 75},
{ /*Barbarian*/ 103, 95, 82, 70, 70, 60, 55},
{ /*Erudite*/ 60, 70, 70, 70, 83, 107, 70},
{ /*Wood Elf*/ 65, 65, 95, 80, 80, 75, 75},
{ /*High Elf*/ 55, 65, 85, 70, 95, 92, 80},
{ /*Dark Elf*/ 60, 65, 90, 75, 83, 99, 60},
{ /*Half Elf*/ 70, 70, 90, 85, 60, 75, 75},
{ /*Dwarf*/ 90, 90, 70, 90, 83, 60, 45},
{ /*Troll*/ 108, 109, 83, 75, 60, 52, 40},
{ /*Ogre*/ 130, 122, 70, 70, 67, 60, 37},
{ /*Halfling*/ 70, 75, 95, 90, 80, 67, 50},
{ /*Gnome*/ 60, 70, 85, 85, 67, 98, 60},
{ /*Iksar*/ 70, 70, 90, 85, 80, 75, 55},
{ /*Vah Shir*/ 90, 75, 90, 70, 70, 65, 65},
{ /*Froglok*/ 70, 80, 100, 100, 75, 75, 50},
{ /*Drakkin*/ 70, 80, 85, 75, 80, 85, 75}
};
static const int BaseClass[PLAYER_CLASS_COUNT][8] =
{ /* STR STA AGI DEX WIS INT CHR ADD*/
{ /*Warrior*/ 10, 10, 5, 0, 0, 0, 0, 25},
{ /*Cleric*/ 5, 5, 0, 0, 10, 0, 0, 30},
{ /*Paladin*/ 10, 5, 0, 0, 5, 0, 10, 20},
{ /*Ranger*/ 5, 10, 10, 0, 5, 0, 0, 20},
{ /*ShadowKnight*/ 10, 5, 0, 0, 0, 10, 5, 20},
{ /*Druid*/ 0, 10, 0, 0, 10, 0, 0, 30},
{ /*Monk*/ 5, 5, 10, 10, 0, 0, 0, 20},
{ /*Bard*/ 5, 0, 0, 10, 0, 0, 10, 25},
{ /*Rouge*/ 0, 0, 10, 10, 0, 0, 0, 30},
{ /*Shaman*/ 0, 5, 0, 0, 10, 0, 5, 30},
{ /*Necromancer*/ 0, 0, 0, 10, 0, 10, 0, 30},
{ /*Wizard*/ 0, 10, 0, 0, 0, 10, 0, 30},
{ /*Magician*/ 0, 10, 0, 0, 0, 10, 0, 30},
{ /*Enchanter*/ 0, 0, 0, 0, 0, 10, 10, 30},
{ /*Beastlord*/ 0, 10, 5, 0, 10, 0, 5, 20},
{ /*Berserker*/ 10, 5, 0, 10, 0, 0, 0, 25}
};
static const bool ClassRaceLookupTable[PLAYER_CLASS_COUNT][_TABLE_RACES]=
{ /*Human Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf Troll Ogre Halfling Gnome Iksar Vahshir Froglok Drakkin*/
{ /*Warrior*/ true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true},
{ /*Cleric*/ true, false, true, false, true, true, true, true, false, false, true, true, false, false, true, true},
{ /*Paladin*/ true, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true},
{ /*Ranger*/ true, false, false, true, false, false, true, false, false, false, true, false, false, false, false, true},
{ /*ShadowKnight*/ true, false, true, false, false, true, false, false, true, true, false, true, true, false, true, true},
{ /*Druid*/ true, false, false, true, false, false, true, false, false, false, true, false, false, false, false, true},
{ /*Monk*/ true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true},
{ /*Bard*/ true, false, false, true, false, false, true, false, false, false, false, false, false, true, false, true},
{ /*Rogue*/ true, true, false, true, false, true, true, true, false, false, true, true, false, true, true, true},
{ /*Shaman*/ false, true, false, false, false, false, false, false, true, true, false, false, true, true, true, false},
{ /*Necromancer*/ true, false, true, false, false, true, false, false, false, false, false, true, true, false, true, true},
{ /*Wizard*/ true, false, true, false, true, true, false, false, false, false, false, true, false, false, true, true},
{ /*Magician*/ true, false, true, false, true, true, false, false, false, false, false, true, false, false, false, true},
{ /*Enchanter*/ true, false, true, false, true, true, false, false, false, false, false, true, false, false, false, true},
{ /*Beastlord*/ false, true, false, false, false, false, false, false, true, true, false, false, true, true, false, false},
{ /*Berserker*/ false, true, false, false, false, false, false, true, true, true, false, false, false, true, false, false}
};//Initial table by kathgar, editted by Wiz for accuracy, solar too
if(!cc) return false;
_log(WORLD__CLIENT,"Validating char creation info...");
classtemp = cc->class_ - 1;
racetemp = cc->race - 1;
// these have non sequential race numbers so they need to be mapped
if (cc->race == FROGLOK) racetemp = 14;
if (cc->race == VAHSHIR) racetemp = 13;
if (cc->race == IKSAR) racetemp = 12;
if (cc->race == DRAKKIN) racetemp = 15;
// if out of range looking it up in the table would crash stuff
// so we return from these
if(classtemp >= PLAYER_CLASS_COUNT)
{
_log(WORLD__CLIENT_ERR," class is out of range");
return false;
}
if(racetemp >= _TABLE_RACES)
{
_log(WORLD__CLIENT_ERR," race is out of range");
return false;
}
if(!ClassRaceLookupTable[classtemp][racetemp]) //Lookup table better than a bunch of ifs?
{
_log(WORLD__CLIENT_ERR," invalid race/class combination");
// we return from this one, since if it's an invalid combination our table
// doesn't have meaningful values for the stats
return false;
}
// solar: add up the base values for this class/race
// this is what they start with, and they have stat_points more
// that can distributed
bSTR = BaseClass[classtemp][0] + BaseRace[racetemp][0];
bSTA = BaseClass[classtemp][1] + BaseRace[racetemp][1];
bAGI = BaseClass[classtemp][2] + BaseRace[racetemp][2];
bDEX = BaseClass[classtemp][3] + BaseRace[racetemp][3];
bWIS = BaseClass[classtemp][4] + BaseRace[racetemp][4];
bINT = BaseClass[classtemp][5] + BaseRace[racetemp][5];
bCHA = BaseClass[classtemp][6] + BaseRace[racetemp][6];
stat_points = BaseClass[classtemp][7];
bTOTAL = bSTR + bSTA + bAGI + bDEX + bWIS + bINT + bCHA;
cTOTAL = cc->STR + cc->STA + cc->AGI + cc->DEX + cc->WIS + cc->INT + cc->CHA;
// solar: the first check makes sure the total is exactly what was expected.
// this will catch all the stat cheating, but there's still the issue
// of reducing CHA or INT or something, to use for STR, so we check
// that none are lower than the base or higher than base + stat_points
// NOTE: these could just be else if, but i want to see all the stats
// that are messed up not just the first hit
if(bTOTAL + stat_points != cTOTAL)
{
_log(WORLD__CLIENT_ERR," stat points total doesn't match expected value: expecting %d got %d", bTOTAL + stat_points, cTOTAL);
Charerrors++;
}
if(cc->STR > bSTR + stat_points || cc->STR < bSTR)
{
_log(WORLD__CLIENT_ERR," stat STR is out of range");
Charerrors++;
}
if(cc->STA > bSTA + stat_points || cc->STA < bSTA)
{
_log(WORLD__CLIENT_ERR," stat STA is out of range");
Charerrors++;
}
if(cc->AGI > bAGI + stat_points || cc->AGI < bAGI)
{
_log(WORLD__CLIENT_ERR," stat AGI is out of range");
Charerrors++;
}
if(cc->DEX > bDEX + stat_points || cc->DEX < bDEX)
{
_log(WORLD__CLIENT_ERR," stat DEX is out of range");
Charerrors++;
}
if(cc->WIS > bWIS + stat_points || cc->WIS < bWIS)
{
_log(WORLD__CLIENT_ERR," stat WIS is out of range");
Charerrors++;
}
if(cc->INT > bINT + stat_points || cc->INT < bINT)
{
_log(WORLD__CLIENT_ERR," stat INT is out of range");
Charerrors++;
}
if(cc->CHA > bCHA + stat_points || cc->CHA < bCHA)
{
_log(WORLD__CLIENT_ERR," stat CHA is out of range");
Charerrors++;
}
/*TODO: Check for deity/class/race.. it'd be nice, but probably of any real use to hack(faction, deity based items are all I can think of)
I am NOT writing those tables - kathgar*/
_log(WORLD__CLIENT,"Found %d errors in character creation request", Charerrors);
return Charerrors == 0;
}
void Client::SetClassStartingSkills( PlayerProfile_Struct *pp )
{
switch( pp->class_ )
{
case BARD:
{
pp->skills[_1H_SLASHING] = 5;
pp->skills[SINGING] = 5;
break;
}
case BEASTLORD:
{
pp->skills[HAND_TO_HAND] = 5;
break;
}
case BERSERKER: // A Guess
{
pp->skills[_2H_SLASHING] = 5;
break;
}
case CLERIC:
{
pp->skills[_1H_BLUNT] = 5;
break;
}
case DRUID:
{
pp->skills[_1H_BLUNT] = 5;
break;
}
case ENCHANTER:
{
pp->skills[PIERCING] = 5;
break;
}
case MAGICIAN:
{
pp->skills[PIERCING] = 5;
break;
}
case MONK:
{
pp->skills[DODGE] = 5;
pp->skills[DUAL_WIELD] = 5;
pp->skills[HAND_TO_HAND] = 5;
break;
}
case NECROMANCER:
{
pp->skills[PIERCING] = 5;
break;
}
case PALADIN:
{
pp->skills[_1H_SLASHING] = 5;
break;
}
case RANGER:
{
pp->skills[_1H_SLASHING] = 5;
break;
}
case ROGUE:
{
pp->skills[PIERCING] = 5;
pp->languages[LANG_THIEVES_CANT] = 100; // Thieves Cant
break;
}
case SHADOWKNIGHT:
{
pp->skills[_1H_SLASHING] = 5;
break;
}
case SHAMAN:
{
pp->skills[_1H_BLUNT] = 5;
break;
}
case WARRIOR:
{
pp->skills[_1H_SLASHING] = 5;
break;
}
case WIZARD:
{
pp->skills[PIERCING] = 5;
break;
}
}
}
void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
{
switch( pp->race )
{
case BARBARIAN:
case DWARF:
case ERUDITE:
case HALF_ELF:
case HIGH_ELF:
case HUMAN:
case OGRE:
case TROLL:
case DRAKKIN: //Drakkin are supposed to get a starting AA Skill
{
// No Race Specific Skills
break;
}
case DARK_ELF:
{
pp->skills[HIDE] = 50;
break;
}
case FROGLOK:
{
pp->skills[SWIMMING] = 125;
break;
}
case GNOME:
{
pp->skills[TINKERING] = 50;
break;
}
case HALFLING:
{
pp->skills[HIDE] = 50;
pp->skills[SNEAK] = 50;
break;
}
case IKSAR:
{
pp->skills[FORAGE] = 50;
pp->skills[SWIMMING] = 100;
break;
}
case WOOD_ELF:
{
pp->skills[FORAGE] = 50;
pp->skills[HIDE] = 50;
break;
}
case VAHSHIR:
{
pp->skills[SAFE_FALL] = 50;
pp->skills[SNEAK] = 50;
break;
}
}
}
void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
{
switch( pp->race )
{
case BARBARIAN:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_BARBARIAN] = 100;
break;
}
case DARK_ELF:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_DARK_ELVISH] = 100;
pp->languages[LANG_DARK_SPEECH] = 100;
pp->languages[LANG_ELDER_ELVISH] = 100;
pp->languages[LANG_ELVISH] = 25;
break;
}
case DWARF:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_DWARVISH] = 100;
pp->languages[LANG_GNOMISH] = 25;
break;
}
case ERUDITE:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_ERUDIAN] = 100;
break;
}
case FROGLOK:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_FROGLOK] = 100;
pp->languages[LANG_TROLL] = 25;
break;
}
case GNOME:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_DWARVISH] = 25;
pp->languages[LANG_GNOMISH] = 100;
break;
}
case HALF_ELF:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_ELVISH] = 100;
break;
}
case HALFLING:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_HALFLING] = 100;
break;
}
case HIGH_ELF:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_DARK_ELVISH] = 25;
pp->languages[LANG_ELDER_ELVISH] = 25;
pp->languages[LANG_ELVISH] = 100;
break;
}
case HUMAN:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
break;
}
case IKSAR:
{
pp->languages[LANG_COMMON_TONGUE] = 95;
pp->languages[LANG_DARK_SPEECH] = 100;
pp->languages[LANG_LIZARDMAN] = 100;
break;
}
case OGRE:
{
pp->languages[LANG_COMMON_TONGUE] = 95;
pp->languages[LANG_DARK_SPEECH] = 100;
pp->languages[LANG_OGRE] = 100;
break;
}
case TROLL:
{
pp->languages[LANG_COMMON_TONGUE] = 95;
pp->languages[LANG_DARK_SPEECH] = 100;
pp->languages[LANG_TROLL] = 100;
break;
}
case WOOD_ELF:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_ELVISH] = 100;
break;
}
case VAHSHIR:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_COMBINE_TONGUE] = 100;
pp->languages[LANG_ERUDIAN] = 25;
pp->languages[LANG_VAH_SHIR] = 100;
break;
}
case DRAKKIN:
{
pp->languages[LANG_COMMON_TONGUE] = 100;
pp->languages[LANG_ELDER_DRAGON] = 100;
pp->languages[LANG_DRAGON] = 100;
break;
}
}
}
Note: client.cpp also includes a fix for dual MOTD, so you need to add the variable;
Code:
INSERT INTO `variables` VALUES ('MOTDEqEmu','Welcome to AXCLASSIC!','Server Message of the Day','2010-01-08 13:19:53');
So you can specify different MOTDs on different LS.
cliententry.cpp
Code:
#include "../common/debug.h"
#include "cliententry.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "worlddb.h"
#include "zoneserver.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
extern int32 numplayers;
extern LoginServer loginserver;
extern ClientList client_list;
extern volatile bool RunLoops;
ClientListEntry::ClientListEntry(int32 in_id, int32 iLSID, const char* iLoginName, const char* iLoginKey, sint16 iWorldAdmin, int32 ip, uint8 local)
: id(in_id)
{
ClearVars(true);
pIP = ip;
pLSID = iLSID;
if(iLSID > 0)
paccountid = database.GetAccountIDFromLSID(iLSID, paccountname, &padmin);
strn0cpy(plsname, iLoginName, sizeof(plsname));
strn0cpy(plskey, iLoginKey, sizeof(plskey));
pworldadmin = iWorldAdmin;
plocal=(local==1);
pinstance = 0;
}
ClientListEntry::ClientListEntry(int32 in_id, int32 iAccID, const char* iAccName, MD5& iMD5Pass, sint16 iAdmin)
: id(in_id)
{
ClearVars(true);
pIP = 0;
pLSID = 0;
pworldadmin = 0;
paccountid = iAccID;
strn0cpy(paccountname, iAccName, sizeof(paccountname));
pMD5Pass = iMD5Pass;
padmin = iAdmin;
pinstance = 0;
}
ClientListEntry::ClientListEntry(int32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline)
: id(in_id)
{
ClearVars(true);
pIP = 0;
pLSID = scl->LSAccountID;
strn0cpy(plsname, scl->name, sizeof(plsname));
strn0cpy(plskey, scl->lskey, sizeof(plskey));
pworldadmin = 0;
paccountid = scl->AccountID;
strn0cpy(paccountname, scl->AccountName, sizeof(paccountname));
padmin = scl->Admin;
pinstance = 0;
if (iOnline >= CLE_Status_Zoning)
Update(iZS, scl, iOnline);
else
SetOnline(iOnline);
}
ClientListEntry::~ClientListEntry() {
if (RunLoops) {
Camp(); // updates zoneserver's numplayers
client_list.RemoveCLEReferances(this);
}
}
void ClientListEntry::SetChar(int32 iCharID, const char* iCharName) {
pcharid = iCharID;
strn0cpy(pname, iCharName, sizeof(pname));
}
void ClientListEntry::SetOnline(ZoneServer* iZS, sint8 iOnline) {
if (iZS == this->Server())
SetOnline(iOnline);
}
void ClientListEntry::SetOnline(sint8 iOnline) {
if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online)
numplayers++;
else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) {
numplayers--;
}
if (iOnline != CLE_Status_Online || pOnline < CLE_Status_Online)
pOnline = iOnline;
if (iOnline < CLE_Status_Zoning)
Camp();
if (pOnline >= CLE_Status_Online)
stale = 0;
}
void ClientListEntry::LSUpdate(ZoneServer* iZS){
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSZoneInfo;
pack->size = sizeof(ZoneInfo_Struct);
pack->pBuffer = new uchar[pack->size];
ZoneInfo_Struct* zone =(ZoneInfo_Struct*)pack->pBuffer;
zone->count=iZS->NumPlayers();
zone->zone = iZS->GetZoneID();
zone->zone_wid = iZS->GetID();
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#else
loginserver.SendPacket(pack);
#endif
safe_delete(pack);
}
}
void ClientListEntry::LSZoneChange(ZoneToZone_Struct* ztz){
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSPlayerZoneChange;
pack->size = sizeof(ServerLSPlayerZoneChange_Struct);
pack->pBuffer = new uchar[pack->size];
ServerLSPlayerZoneChange_Struct* zonechange =(ServerLSPlayerZoneChange_Struct*)pack->pBuffer;
zonechange->lsaccount_id = LSID();
zonechange->from = ztz->current_zone_id;
zonechange->to = ztz->requested_zone_id;
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
}
void ClientListEntry::Update(ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline) {
if (pzoneserver != iZS) {
if (pzoneserver){
pzoneserver->RemovePlayer();
LSUpdate(pzoneserver);
}
if (iZS){
iZS->AddPlayer();
LSUpdate(iZS);
}
}
pzoneserver = iZS;
pzone = scl->zone;
pinstance = scl->instance_id;
pcharid = scl->charid;
strcpy(pname, scl->name);
if (paccountid == 0) {
paccountid = scl->AccountID;
strcpy(paccountname, scl->AccountName);
strcpy(plsname, scl->AccountName);
pIP = scl->IP;
pLSID = scl->LSAccountID;
strn0cpy(plskey, scl->lskey, sizeof(plskey));
}
padmin = scl->Admin;
plevel = scl->level;
pclass_ = scl->class_;
prace = scl->race;
panon = scl->anon;
ptellsoff = scl->tellsoff;
pguild_id = scl->guild_id;
pLFG = scl->LFG;
gm = scl->gm;
// Fields from the LFG Window
if((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
pLFGFromLevel = scl->LFGFromLevel;
pLFGToLevel = scl->LFGToLevel;
pLFGMatchFilter = scl->LFGMatchFilter;
memcpy(pLFGComments, scl->LFGComments, sizeof(pLFGComments));
}
SetOnline(iOnline);
}
void ClientListEntry::LeavingZone(ZoneServer* iZS, sint8 iOnline) {
if (iZS != 0 && iZS != pzoneserver)
return;
SetOnline(iOnline);
if (pzoneserver){
pzoneserver->RemovePlayer();
LSUpdate(pzoneserver);
}
pzoneserver = 0;
pzone = 0;
}
void ClientListEntry::ClearVars(bool iAll) {
if (iAll) {
pOnline = CLE_Status_Never;
stale = 0;
pLSID = 0;
memset(plsname, 0, sizeof(plsname));
memset(plskey, 0, sizeof(plskey));
pworldadmin = 0;
paccountid = 0;
memset(paccountname, 0, sizeof(paccountname));
padmin = 0;
}
pzoneserver = 0;
pzone = 0;
pcharid = 0;
memset(pname, 0, sizeof(pname));
plevel = 0;
pclass_ = 0;
prace = 0;
panon = 0;
ptellsoff = 0;
pguild_id = GUILD_NONE;
pLFG = 0;
gm = 0;
}
void ClientListEntry::Camp(ZoneServer* iZS) {
if (iZS != 0 && iZS != pzoneserver)
return;
if (pzoneserver){
pzoneserver->RemovePlayer();
LSUpdate(pzoneserver);
}
ClearVars();
stale = 0;
}
bool ClientListEntry::CheckStale() {
stale++;
if (stale >= 3) {
if (pOnline > CLE_Status_Offline)
SetOnline(CLE_Status_Offline);
else
return true;
}
return false;
}
bool ClientListEntry::CheckAuth(int32 iLSID, const char* iKey) {
// if (LSID() == iLSID && strncmp(plskey, iKey,10) == 0) {
if (strncmp(plskey, iKey,10) == 0) {
if (paccountid == 0 && LSID()>0) {
sint16 tmpStatus = WorldConfig::get()->DefaultStatus;
paccountid = database.CreateAccount(plsname, 0, tmpStatus, LSID());
if (!paccountid) {
_log(WORLD__CLIENTLIST_ERR,"Error adding local account for LS login: '%s', either duplicate name or adding a second LS account will do this, if latter, try again." ,plsname);
return false;
}
strn0cpy(paccountname, plsname, sizeof(paccountname));
padmin = tmpStatus;
}
char lsworldadmin[15] = "0";
database.GetVariable("honorlsworldadmin", lsworldadmin, sizeof(lsworldadmin));
if (atoi(lsworldadmin) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0))
padmin = pworldadmin;
return true;
}
return false;
}
bool ClientListEntry::CheckAuth(const char* iName, MD5& iMD5Password) {
if (LSAccountID() == 0 && strcmp(paccountname, iName) == 0 && pMD5Pass == iMD5Password)
return true;
return false;
}
bool ClientListEntry::CheckAuth(int32 id, const char* iKey, int32 ip) {
if (pIP==ip && strncmp(plskey, iKey,10) == 0){
paccountid = id;
database.GetAccountFromID(id,paccountname,&padmin);
return true;
}
return false;
}
zoneserver.cpp
Code:
#include "../common/debug.h"
#include "zoneserver.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "zonelist.h"
#include "worlddb.h"
#include "console.h"
#include "client.h"
#include "../common/md5.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
#include "../common/packet_dump.h"
#include "../common/misc.h"
#include "cliententry.h"
#include "wguild_mgr.h"
#include "lfplist.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
extern ZSList zoneserver_list;
extern ConsoleList console_list;
extern LoginServer loginserver;
extern volatile bool RunLoops;
ZoneServer::ZoneServer(EmuTCPConnection* itcpc)
: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) {
ID = zoneserver_list.GetNextID();
memset(zone_name, 0, sizeof(zone_name));
memset(compiled, 0, sizeof(compiled));
zoneID = 0;
instanceID = 0;
memset(clientaddress, 0, sizeof(clientaddress));
clientport = 0;
BootingUp = false;
authenticated = false;
staticzone = false;
pNumPlayers = 0;
}
ZoneServer::~ZoneServer() {
if (RunLoops)
client_list.CLERemoveZSRef(this);
tcpc->Free();
}
bool ZoneServer::SetZone(int32 iZoneID, int32 iInstanceID, bool iStaticZone) {
BootingUp = false;
const char* zn = MakeLowerString(database.GetZoneName(iZoneID));
char* longname;
if (iZoneID)
zlog(WORLD__ZONE,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID,
iStaticZone ? " (Static)" : "");
zoneID = iZoneID;
instanceID = iInstanceID;
if(iZoneID!=0)
oldZoneID = iZoneID;
if (zoneID == 0) {
client_list.CLERemoveZSRef(this);
pNumPlayers = 0;
LSSleepUpdate(GetPrevZoneID());
}
staticzone = iStaticZone;
if (zn)
{
strcpy(zone_name, zn);
if( database.GetZoneLongName( (char*)zone_name, &longname, NULL, NULL, NULL, NULL, NULL, NULL ) )
{
strcpy(long_name, longname);
safe_delete( longname );
}
else
strcpy(long_name, "");
}
else
{
strcpy(zone_name, "");
strcpy(long_name, "");
}
client_list.ZoneBootup(this);
ls_zboot.Start();
return true;
}
void ZoneServer::LSShutDownUpdate(int32 zoneid){
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSZoneShutdown;
pack->size = sizeof(ZoneShutdown_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer,0,pack->size);
ZoneShutdown_Struct* zsd =(ZoneShutdown_Struct*)pack->pBuffer;
if(zoneid==0)
zsd->zone = GetPrevZoneID();
else
zsd->zone = zoneid;
zsd->zone_wid = GetID();
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
}
void ZoneServer::LSBootUpdate(int32 zoneid, int32 instanceid, bool startup){
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
if(startup)
pack->opcode = ServerOP_LSZoneStart;
else
pack->opcode = ServerOP_LSZoneBoot;
pack->size = sizeof(ZoneBoot_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer,0,pack->size);
ZoneBoot_Struct* bootup =(ZoneBoot_Struct*)pack->pBuffer;
if(startup)
strcpy(bootup->compile_time,GetCompileTime());
bootup->zone = zoneid;
bootup->zone_wid = GetID();
bootup->instance = instanceid;
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
}
void ZoneServer::LSSleepUpdate(int32 zoneid){
if(WorldConfig::get()->UpdateStats){
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSZoneSleep;
pack->size = sizeof(ServerLSZoneSleep_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer,0,pack->size);
ServerLSZoneSleep_Struct* sleep =(ServerLSZoneSleep_Struct*)pack->pBuffer;
sleep->zone = zoneid;
sleep->zone_wid = GetID();
loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
loginserver.SendPacket2(pack);
#endif
safe_delete(pack);
}
}
bool ZoneServer::Process() {
if (!tcpc->Connected())
return false;
if(ls_zboot.Check()){
LSBootUpdate(GetZoneID(), true);
ls_zboot.Disable();
}
ServerPacket *pack = 0;
while((pack = tcpc->PopPacket())) {
_hex(WORLD__ZONE_TRACE,pack->pBuffer,pack->size);
if (!authenticated) {
if (WorldConfig::get()->SharedKey.length() > 0) {
if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) {
int8 tmppass[16];
MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass);
if (memcmp(pack->pBuffer, tmppass, 16) == 0)
authenticated = true;
else {
struct in_addr in;
in.s_addr = GetIP();
zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack);
delete pack;
Disconnect();
return false;
}
}
else {
struct in_addr in;
in.s_addr = GetIP();
zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack);
delete pack;
Disconnect();
return false;
}
}
else
{
_log(WORLD__ZONE,"**WARNING** You have not configured a world shared key in your config file. You should add a <key>STRING</key> element to your <world> element to prevent unauthroized zone access.");
authenticated = true;
}
}
switch(pack->opcode) {
case 0:
break;
case ServerOP_KeepAlive: {
// ignore this
break;
}
case ServerOP_ZAAuth: {
break;
}
case ServerOP_LSZoneBoot:{
if(pack->size==sizeof(ZoneBoot_Struct)){
ZoneBoot_Struct* zbs= (ZoneBoot_Struct*)pack->pBuffer;
SetCompile(zbs->compile_time);
}
break;
}
/*
case ServerOP_SendGroup: {
SendGroup_Struct* sgs=(SendGroup_Struct*)pack->pBuffer;
ZoneServer* zs=zoneserver_list.FindByZoneID(sgs->zoneid);
if(!zs)
zlog(WORLD__ZONE,"Could not find zone id: %i running to transfer group to!",sgs->zoneid);
else{
zs->SendPacket(pack);
}
break;
}*/
case ServerOP_GroupIDReq: {
SendGroupIDs();
break;
}
case ServerOP_GroupLeave: {
if(pack->size != sizeof(ServerGroupLeave_Struct))
break;
zoneserver_list.SendPacket(pack); //bounce it to all zones
break;
}
case ServerOP_GroupJoin: {
if(pack->size != sizeof(ServerGroupJoin_Struct))
break;
zoneserver_list.SendPacket(pack); //bounce it to all zones
break;
}
case ServerOP_ForceGroupUpdate: {
if(pack->size != sizeof(ServerForceGroupUpdate_Struct))
break;
zoneserver_list.SendPacket(pack); //bounce it to all zones
break;
}
case ServerOP_OOZGroupMessage: {
zoneserver_list.SendPacket(pack); //bounce it to all zones
break;
}
case ServerOP_DisbandGroup: {
if(pack->size != sizeof(ServerDisbandGroup_Struct))
break;
zoneserver_list.SendPacket(pack); //bounce it to all zones
break;
}
case ServerOP_RaidAdd:{
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidRemove: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidDisband: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidLockFlag: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidChangeGroup: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_UpdateGroup: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidGroupDisband: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidGroupAdd: {
if(pack->size != sizeof(ServerRaidGroupAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidGroupRemove: {
if(pack->size != sizeof(ServerRaidGroupAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidGroupSay: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidSay: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidGroupLeader: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RaidLeader: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_DetailsChange: {
if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
break;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_SpawnCondition: {
if(pack->size != sizeof(ServerSpawnCondition_Struct))
break;
//bounce the packet to the correct zone server, if its up
ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer;
zoneserver_list.SendPacket(ssc->zoneID, 0, pack);
break;
}
case ServerOP_SpawnEvent: {
if(pack->size != sizeof(ServerSpawnEvent_Struct))
break;
//bounce the packet to the correct zone server, if its up
ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer;
zoneserver_list.SendPacket(sse->zoneID, 0, pack);
break;
}
case ServerOP_ChannelMessage: {
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer;
if (scm->chan_num == 7 || scm->chan_num == 14) {
if (scm->deliverto[0] == '*') {
Console* con = 0;
con = console_list.FindByAccountName(&scm->deliverto[1]);
if (((!con) || (!con->SendChannelMessage(scm))) && (!scm->noreply))
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
break;
}
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
if (cle == 0 || cle->Online() < CLE_Status_Zoning || (cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply)
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
}
else if (cle->Online() == CLE_Status_Zoning) {
if (!scm->noreply) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
//MYSQL_ROW row; Trumpcard - commenting. Currently unused.
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char *telldate=asctime(timeinfo);
if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT name from character_ where name='%s'",scm->deliverto), errbuf, &result)) {
safe_delete(query);
if (result!=0) {
if (database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO tellque (Date,Receiver,Sender,Message) values('%s','%s','%s','%s')",telldate,scm->deliverto,scm->from,scm->message), errbuf, &result))
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "Your message has been added to the %s's que.", scm->to);
else
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
safe_delete(query);
}
else
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
mysql_free_result(result);
}
else
safe_delete(query);
}
// zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
}
else if (cle->Server() == 0) {
if (!scm->noreply)
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not contactable at this time'", scm->to, scm->to);
}
else
cle->Server()->SendPacket(pack);
}
else {
if (scm->chan_num == 5 || scm->chan_num == 6 || scm->chan_num == 11) {
console_list.SendChannelMessage(scm);
}
zoneserver_list.SendPacket(pack);
}
break;
}
case ServerOP_EmoteMessage: {
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
zoneserver_list.SendEmoteMessageRaw(sem->to, sem->guilddbid, sem->minstatus, sem->type, sem->message);
break;
}
case ServerOP_VoiceMacro: {
ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer;
if(svm->Type == VoiceMacroTell) {
ClientListEntry* cle = client_list.FindCharacter(svm->To);
if (!cle || (cle->Online() < CLE_Status_Zoning) || !cle->Server()) {
zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);
break;
}
cle->Server()->SendPacket(pack);
}
else
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RezzPlayerAccept: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RezzPlayer: {
RezzPlayer_Struct* sRezz = (RezzPlayer_Struct*) pack->pBuffer;
if (zoneserver_list.SendPacket(pack)){
zlog(WORLD__ZONE,"Sent Rez packet for %s",sRezz->rez.your_name);
}
else {
zlog(WORLD__ZONE,"Could not send Rez packet for %s",sRezz->rez.your_name);
}
break;
}
case ServerOP_MultiLineMsg: {
ServerMultiLineMsg_Struct* mlm = (ServerMultiLineMsg_Struct*) pack->pBuffer;
client_list.SendPacket(mlm->to, pack);
break;
}
case ServerOP_SetZone: {
if(pack->size != sizeof(SetZone_Struct))
break;
SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer;
if (szs->zoneid != 0) {
if(database.GetZoneName(szs->zoneid))
SetZone(szs->zoneid, szs->instanceid, szs->staticzone);
else
SetZone(0);
}
else
SetZone(0);
break;
}
case ServerOP_SetConnectInfo: {
if (pack->size != sizeof(ServerConnectInfo))
break;
ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer;
if (!sci->port) {
clientport=zoneserver_list.GetAvailableZonePort();
ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo));
memset(p.pBuffer,0,sizeof(ServerConnectInfo));
ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer;
sci->port = clientport;
SendPacket(&p);
zlog(WORLD__ZONE,"Auto zone port configuration. Telling zone to use port %d",clientport);
} else {
clientport=sci->port;
zlog(WORLD__ZONE,"Zone specified port %d, must be a previously allocated zone reconnecting.",clientport);
}
}
case ServerOP_SetLaunchName: {
if(pack->size != sizeof(LaunchName_Struct))
break;
const LaunchName_Struct* ln = (const LaunchName_Struct*)pack->pBuffer;
launcher_name = ln->launcher_name;
launched_name = ln->zone_name;
zlog(WORLD__ZONE, "Zone started with name %s by launcher %s", launched_name.c_str(), launcher_name.c_str());
break;
}
case ServerOP_ShutdownAll: {
if(pack->size==0){
zoneserver_list.SendPacket(pack);
zoneserver_list.Process();
CatchSignal(2);
}
else{
WorldShutDown_Struct* wsd=(WorldShutDown_Struct*)pack->pBuffer;
if(wsd->time==0 && wsd->interval==0 && zoneserver_list.shutdowntimer->Enabled()){
zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable();
}
else{
zoneserver_list.shutdowntimer->SetTimer(wsd->time);
zoneserver_list.reminder->SetTimer(wsd->interval-1000);
zoneserver_list.reminder->SetAtTrigger(wsd->interval);
zoneserver_list.shutdowntimer->Start();
zoneserver_list.reminder->Start();
}
}
break;
}
case ServerOP_ZoneShutdown: {
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
ZoneServer* zs = 0;
if (s->ZoneServerID != 0)
zs = zoneserver_list.FindByID(s->ZoneServerID);
else if (s->zoneid != 0)
zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
else
zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: neither ID nor name specified");
if (zs == 0)
zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: zoneserver not found");
else
zs->SendPacket(pack);
break;
}
case ServerOP_ZoneBootup: {
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
zoneserver_list.SOPZoneBootup(s->adminname, s->ZoneServerID, database.GetZoneName(s->zoneid), s->makestatic);
break;
}
case ServerOP_ZoneStatus: {
if (pack->size >= 1)
zoneserver_list.SendZoneStatus((char *) &pack->pBuffer[1], (int8) pack->pBuffer[0], this);
break;
}
case ServerOP_AcceptWorldEntrance: {
if(pack->size != sizeof(WorldToZone_Struct))
break;
WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
Client* client = 0;
client = client_list.FindByAccountID(wtz->account_id);
if(client != 0)
client->Clearance(wtz->response);
}
case ServerOP_ZoneToZoneRequest: {
//
// solar: ZoneChange is received by the zone the player is in, then the
// zone sends a ZTZ which ends up here. This code then find the target
// (ingress point) and boots it if needed, then sends the ZTZ to it.
// The ingress server will decide wether the player can enter, then will
// send back the ZTZ to here. This packet is passed back to the egress
// server, which will send a ZoneChange response back to the client
// which can be an error, or a success, in which case the client will
// disconnect, and their zone location will be saved when ~Client is
// called, so it will be available when they ask to zone.
//
if(pack->size != sizeof(ZoneToZone_Struct))
break;
ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer;
ClientListEntry* client = NULL;
if(WorldConfig::get()->UpdateStats)
client = client_list.FindCharacter(ztz->name);
zlog(WORLD__ZONE,"ZoneToZone request for %s current zone %d req zone %d\n",
ztz->name, ztz->current_zone_id, ztz->requested_zone_id);
if(GetZoneID() == ztz->current_zone_id && GetInstanceID() == ztz->current_instance_id) // this is a request from the egress zone
{
zlog(WORLD__ZONE,"Processing ZTZ for egress from zone for client %s\n", ztz->name);
if
(
ztz->admin < 80 &&
ztz->ignorerestrictions < 2 &&
zoneserver_list.IsZoneLocked(ztz->requested_zone_id)
)
{
ztz->response = 0;
SendPacket(pack);
break;
}
ZoneServer *ingress_server = NULL;
if(ztz->requested_instance_id > 0)
{
ingress_server = zoneserver_list.FindByInstanceID(ztz->requested_instance_id);
}
else
{
ingress_server = zoneserver_list.FindByZoneID(ztz->requested_zone_id);
}
if(ingress_server) // found a zone already running
{
_log(WORLD__ZONE,"Found a zone already booted for %s\n", ztz->name);
ztz->response = 1;
}
else // need to boot one
{
int server_id;
if ((server_id = zoneserver_list.TriggerBootup(ztz->requested_zone_id, ztz->requested_instance_id))){
_log(WORLD__ZONE,"Successfully booted a zone for %s\n", ztz->name);
// bootup successful, ready to rock
ztz->response = 1;
ingress_server = zoneserver_list.FindByID(server_id);
}
else
{
_log(WORLD__ZONE_ERR,"FAILED to boot a zone for %s\n", ztz->name);
// bootup failed, send back error code 0
ztz->response = 0;
}
}
if(ztz->response!=0 && client)
client->LSZoneChange(ztz);
SendPacket(pack); // send back to egress server
if(ingress_server) // if we couldn't boot one, this is 0
{
ingress_server->SendPacket(pack); // inform target server
}
}
else // this is response from the ingress server, route it back to the egress server
{
zlog(WORLD__ZONE,"Processing ZTZ for ingress to zone for client %s\n", ztz->name);
ZoneServer *egress_server = NULL;
if(ztz->current_instance_id > 0)
{
egress_server = zoneserver_list.FindByInstanceID(ztz->current_instance_id);
}
else
{
egress_server = zoneserver_list.FindByZoneID(ztz->current_zone_id);
}
if(egress_server)
{
egress_server->SendPacket(pack);
}
}
break;
}
case ServerOP_ClientList: {
if (pack->size != sizeof(ServerClientList_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientList. Got: %d, Expected: %d",pack->size,sizeof(ServerClientList_Struct));
break;
}
client_list.ClientUpdate(this, (ServerClientList_Struct*) pack->pBuffer);
break;
}
case ServerOP_ClientListKA: {
ServerClientListKeepAlive_Struct* sclka = (ServerClientListKeepAlive_Struct*) pack->pBuffer;
if (pack->size < 4 || pack->size != 4 + (4 * sclka->numupdates)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientListKA. Got: %d, Expected: %d",pack->size, (4 + (4 * sclka->numupdates)));
break;
}
client_list.CLEKeepAlive(sclka->numupdates, sclka->wid);
break;
}
case ServerOP_Who: {
ServerWhoAll_Struct* whoall = (ServerWhoAll_Struct*) pack->pBuffer;
Who_All_Struct* whom = new Who_All_Struct;
memset(whom,0,sizeof(Who_All_Struct));
whom->gmlookup = whoall->gmlookup;
whom->lvllow = whoall->lvllow;
whom->lvlhigh = whoall->lvlhigh;
whom->wclass = whoall->wclass;
whom->wrace = whoall->wrace;
strcpy(whom->whom,whoall->whom);
client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this);
delete whom;
break;
}
case ServerOP_FriendsWho: {
ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer;
client_list.SendFriendsWho(FriendsWho, this);
break;
}
case ServerOP_LFGMatches: {
ServerLFGMatchesRequest_Struct* smrs = (ServerLFGMatchesRequest_Struct*) pack->pBuffer;
client_list.SendLFGMatches(smrs);
break;
}
case ServerOP_LFPMatches: {
ServerLFPMatchesRequest_Struct* smrs = (ServerLFPMatchesRequest_Struct*) pack->pBuffer;
LFPGroupList.SendLFPMatches(smrs);
break;
}
case ServerOP_LFPUpdate: {
ServerLFPUpdate_Struct* sus = (ServerLFPUpdate_Struct*) pack->pBuffer;
if(sus->Action)
LFPGroupList.UpdateGroup(sus);
else
LFPGroupList.RemoveGroup(sus);
break;
}
case ServerOP_ZonePlayer: {
//ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer;
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_KickPlayer: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_KillPlayer: {
zoneserver_list.SendPacket(pack);
break;
}
//these opcodes get processed by the guild manager.
case ServerOP_RefreshGuild:
case ServerOP_DeleteGuild:
case ServerOP_GuildCharRefresh:
case ServerOP_GuildMemberUpdate: {
guild_mgr.ProcessZonePacket(pack);
break;
}
case ServerOP_FlagUpdate: {
ClientListEntry* cle = client_list.FindCLEByAccountID(*((int32*) pack->pBuffer));
if (cle)
cle->SetAdmin(*((sint16*) &pack->pBuffer[4]));
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_GMGoto: {
if (pack->size != sizeof(ServerGMGoto_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_GMGoto. Got: %d, Expected: %d",pack->size,sizeof(ServerGMGoto_Struct));
break;
}
ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer;
ClientListEntry* cle = client_list.FindCharacter(gmg->gotoname);
if (cle != 0) {
if (cle->Server() == 0)
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: Cannot identify %s's zoneserver.", gmg->gotoname);
else if (cle->Anon() == 1 && cle->Admin() > gmg->admin) // no snooping for anon GMs
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
else
cle->Server()->SendPacket(pack);
}
else {
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
}
break;
}
case ServerOP_Lock: {
if (pack->size != sizeof(ServerLock_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Lock. Got: %d, Expected: %d",pack->size,sizeof(ServerLock_Struct));
break;
}
ServerLock_Struct* slock = (ServerLock_Struct*) pack->pBuffer;
if (slock->mode >= 1)
WorldConfig::LockWorld();
else
WorldConfig::UnlockWorld();
if (loginserver.Connected()) {
loginserver.SendStatus();
if (slock->mode >= 1)
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked");
else
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked");
}
else {
if (slock->mode >= 1)
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked, but login server not connected.");
else
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked, but login server not conencted.");
}
break;
}
case ServerOP_Motd: {
if (pack->size != sizeof(ServerMotd_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Motd. Got: %d, Expected: %d",pack->size,sizeof(ServerMotd_Struct));
break;
}
ServerMotd_Struct* smotd = (ServerMotd_Struct*) pack->pBuffer;
database.SetVariable("MOTD",smotd->motd);
//this->SendEmoteMessage(smotd->myname, 0, 0, 13, "Updated Motd.");
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_Uptime: {
if (pack->size != sizeof(ServerUptime_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Uptime. Got: %d, Expected: %d",pack->size,sizeof(ServerUptime_Struct));
break;
}
ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
if (sus->zoneserverid == 0) {
ZSList::ShowUpTime(this, sus->adminname);
}
else {
ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
if (zs)
zs->SendPacket(pack);
}
break;
}
case ServerOP_Petition: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_GetWorldTime: {
zlog(WORLD__ZONE,"Broadcasting a world time update");
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_SyncWorldTime;
pack->size = sizeof(eqTimeOfDay);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
eqTimeOfDay* tod = (eqTimeOfDay*) pack->pBuffer;
tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime();
tod->start_realtime=zoneserver_list.worldclock.getStartRealTime();
SendPacket(pack);
delete pack;
break;
}
case ServerOP_SetWorldTime: {
zlog(WORLD__ZONE,"Received SetWorldTime");
eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
zoneserver_list.worldclock.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
zlog(WORLD__ZONE,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime);
zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str());
zoneserver_list.SendTimeSync();
break;
}
case ServerOP_IPLookup: {
if (pack->size < sizeof(ServerGenericWorldQuery_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_IPLookup. Got: %d, Expected (at least): %d",pack->size,sizeof(ServerGenericWorldQuery_Struct));
break;
}
ServerGenericWorldQuery_Struct* sgwq = (ServerGenericWorldQuery_Struct*) pack->pBuffer;
if (pack->size == sizeof(ServerGenericWorldQuery_Struct))
client_list.SendCLEList(sgwq->admin, sgwq->from, this);
else
client_list.SendCLEList(sgwq->admin, sgwq->from, this, sgwq->query);
break;
}
case ServerOP_LockZone: {
if (pack->size < sizeof(ServerLockZone_Struct)) {
zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_LockZone. Got: %d, Expected: %d",pack->size,sizeof(ServerLockZone_Struct));
break;
}
ServerLockZone_Struct* s = (ServerLockZone_Struct*) pack->pBuffer;
switch (s->op) {
case 0:
zoneserver_list.ListLockedZones(s->adminname, this);
break;
case 1:
if (zoneserver_list.SetLockedZone(s->zoneID, true))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(s->zoneID));
else
this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
break;
case 2:
if (zoneserver_list.SetLockedZone(s->zoneID, false))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(s->zoneID));
else
this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
break;
}
break;
}
case ServerOP_ItemStatus: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_OOCMute: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_Revoke: {
RevokeStruct* rev = (RevokeStruct*)pack->pBuffer;
ClientListEntry* cle = client_list.FindCharacter(rev->name);
if (cle != 0 && cle->Server() != 0)
{
cle->Server()->SendPacket(pack);
}
break;
}
case ServerOP_SpawnPlayerCorpse: {
SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
if(zs) {
if (zs->SendPacket(pack)) {
zlog(WORLD__ZONE,"Sent request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
}
else {
zlog(WORLD__ZONE_ERR,"Could not send request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
}
}
break;
}
case ServerOP_Consent: {
// Message string id's likely to be used here are:
// CONSENT_YOURSELF = 399
// CONSENT_INVALID_NAME = 397
// TARGET_NOT_FOUND = 101
ZoneServer* zs;
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
ClientListEntry* cle = client_list.FindCharacter(s->grantname);
if(cle) {
if(cle->instance() != 0)
{
zs = zoneserver_list.FindByInstanceID(cle->instance());
if(zs) {
if(zs->SendPacket(pack)) {
zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->instance());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent operation.", s->instance_id);
}
}
else
{
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
scs->permission = s->permission;
scs->zone_id = s->zone_id;
scs->instance_id = s->instance_id;
scs->message_string_id = 101;
zs = zoneserver_list.FindByInstanceID(s->instance_id);
if(zs) {
if(!zs->SendPacket(pack))
zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
}
}
}
else
{
zs = zoneserver_list.FindByZoneID(cle->zone());
if(zs) {
if(zs->SendPacket(pack)) {
zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->zone());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent operation.", s->zone_id);
}
}
else {
// send target not found back to requester
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
scs->permission = s->permission;
scs->zone_id = s->zone_id;
scs->message_string_id = 101;
zs = zoneserver_list.FindByZoneID(s->zone_id);
if(zs) {
if(!zs->SendPacket(pack))
zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
}
}
}
}
else {
// send target not found back to requester
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
scs->permission = s->permission;
scs->zone_id = s->zone_id;
scs->message_string_id = 397;
zs = zoneserver_list.FindByZoneID(s->zone_id);
if(zs) {
if(!zs->SendPacket(pack))
zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
}
}
break;
}
case ServerOP_Consent_Response: {
// Message string id's likely to be used here are:
// CONSENT_YOURSELF = 399
// CONSENT_INVALID_NAME = 397
// TARGET_NOT_FOUND = 101
ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
if(s->instance_id != 0)
{
ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id);
if(zs) {
if(!zs->SendPacket(pack))
zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
}
}
else
{
ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
if(zs) {
if(!zs->SendPacket(pack))
zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
}
else {
zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
}
}
break;
}
case ServerOP_InstanceUpdateTime :
{
ServerInstanceUpdateTime_Struct *iut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer;
ZoneServer *zm = zoneserver_list.FindByInstanceID(iut->instance_id);
if(zm)
{
zm->SendPacket(pack);
}
break;
}
case ServerOP_QGlobalUpdate:
{
if(pack->size != sizeof(ServerQGlobalUpdate_Struct))
{
break;
}
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_QGlobalDelete:
{
if(pack->size != sizeof(ServerQGlobalDelete_Struct))
{
break;
}
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_AdventureCreate:
case ServerOP_AdventureAddPlayer:
case ServerOP_AdventureDestroy:
case ServerOP_AdventureUpdate:
case ServerOP_AdventureCount:
case ServerOP_AdventureFinish:
case ServerOP_AdventureMessage:
case ServerOP_DepopAllPlayersCorpses:
case ServerOP_ReloadTitles:
case ServerOP_SpawnStatusChange:
case ServerOP_ReloadTasks:
case ServerOP_UpdateSpawn:
{
zoneserver_list.SendPacket(pack);
break;
}
default:
{
zlog(WORLD__ZONE_ERR,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size);
DumpPacket(pack->pBuffer, pack->size);
break;
}
}
delete pack;
}
return true;
}
void ZoneServer::SendEmoteMessage(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message, ...) {
if (!message)
return;
va_list argptr;
char buffer[1024];
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
}
void ZoneServer::SendEmoteMessageRaw(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message) {
if (!message)
return;
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_EmoteMessage;
pack->size = sizeof(ServerEmoteMessage_Struct)+strlen(message)+1;
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
if (to != 0) {
strcpy((char *) sem->to, to);
}
else {
sem->to[0] = 0;
}
sem->guilddbid = to_guilddbid;
sem->minstatus = to_minstatus;
sem->type = type;
strcpy(&sem->message[0], message);
pack->Deflate();
SendPacket(pack);
delete pack;
}
void ZoneServer::SendGroupIDs() {
ServerPacket* pack = new ServerPacket(ServerOP_GroupIDReply, sizeof(ServerGroupIDReply_Struct));
ServerGroupIDReply_Struct* sgi = (ServerGroupIDReply_Struct*)pack->pBuffer;
zoneserver_list.NextGroupIDs(sgi->start, sgi->end);
SendPacket(pack);
delete pack;
}
void ZoneServer::ChangeWID(int32 iCharID, int32 iWID) {
ServerPacket* pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*) pack->pBuffer;
scw->charid = iCharID;
scw->newwid = iWID;
zoneserver_list.SendPacket(pack);
delete pack;
}
void ZoneServer::TriggerBootup(int32 iZoneID, int32 iInstanceID, const char* adminname, bool iMakeStatic) {
BootingUp = true;
zoneID = iZoneID;
instanceID = iInstanceID;
ServerPacket* pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct));
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
s->ZoneServerID = ID;
if (adminname != 0)
strcpy(s->adminname, adminname);
if (iZoneID == 0)
s->zoneid = this->GetZoneID();
else
s->zoneid = iZoneID;
s->instanceid = iInstanceID;
s->makestatic = iMakeStatic;
SendPacket(pack);
delete pack;
LSBootUpdate(iZoneID, iInstanceID);
}
void ZoneServer::IncommingClient(Client* client) {
BootingUp = true;
ServerPacket* pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncommingClient_Struct));
ServerZoneIncommingClient_Struct* s = (ServerZoneIncommingClient_Struct*) pack->pBuffer;
s->zoneid = GetZoneID();
s->instanceid = GetInstanceID();
s->wid = client->GetWID();
s->ip = client->GetIP();
s->accid = client->GetAccountID();
s->admin = client->GetAdmin();
s->charid = client->GetCharID();
if (client->GetCLE())
s->tellsoff = client->GetCLE()->TellsOff();
strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));
strn0cpy(s->lskey, client->GetLSKey(), sizeof(s->lskey));
SendPacket(pack);
delete pack;
}
This was WORLD, COMMON will be on next post
Last edited by Angelox; 04-17-2010 at 08:51 PM..
|