|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum) |
|
|
|
04-17-2010, 10:43 AM
|
AX Classic Developer
|
|
Join Date: May 2006
Location: filler
Posts: 2,049
|
|
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..
|
|
|
|
|
|
|
04-17-2010, 11:12 AM
|
AX Classic Developer
|
|
Join Date: May 2006
Location: filler
Posts: 2,049
|
|
Note; if you have an account on your server on one lsaccount table, but the second lsaccount table is still empty, when you access the empty one for the first time, you will get bumped back to LS while it makes the account ID. after that, it works fine.
EqEmuConfig.cpp
Code:
#include "../common/debug.h"
#include "EQEmuConfig.h"
#include "MiscFunctions.h"
#include <iostream>
string EQEmuConfig::ConfigFile = "eqemu_config.xml";
EQEmuConfig *EQEmuConfig::_config = NULL;
void EQEmuConfig::do_world(TiXmlElement *ele) {
const char *text;
TiXmlElement * sub_ele;;
text= ParseTextBlock(ele,"shortname");
if (text)
ShortName=text;
text = ParseTextBlock(ele,"longname");
if (text)
LongName=text;
text = ParseTextBlock(ele,"address",true);
if (text)
WorldAddress=text;
text = ParseTextBlock(ele,"localaddress",true);
if (text)
LocalAddress=text;
text = ParseTextBlock(ele,"maxclients",true);
if (text)
MaxClients=atoi(text);
// Get the <key> element
text = ParseTextBlock(ele,"key",true);
if (text)
SharedKey=text;
// Get the <loginserver> element
sub_ele = ele->FirstChildElement("loginserver");
if (sub_ele) {
text=ParseTextBlock(sub_ele,"host",true);
if (text)
LoginHost=text;
text=ParseTextBlock(sub_ele,"port",true);
if (text)
LoginPort=atoi(text);
text=ParseTextBlock(sub_ele,"account",true);
if (text)
LoginAccount=text;
text=ParseTextBlock(sub_ele,"password",true);
if (text)
LoginPassword=text;
#ifdef DUAL_SERVER
text=ParseTextBlock(sub_ele,"host2",true);
if (text)
LoginHost2=text;
text=ParseTextBlock(sub_ele,"port2",true);
if (text)
LoginPort2=atoi(text);
text=ParseTextBlock(sub_ele,"account2",true);
if (text)
LoginAccount2=text;
text=ParseTextBlock(sub_ele,"password2",true);
if (text)
LoginPassword2=text;
#endif
}
// Check for locked
sub_ele = ele->FirstChildElement("locked");
if (sub_ele != NULL)
Locked=true;
// Get the <tcp> element
sub_ele = ele->FirstChildElement("tcp");
if(sub_ele != NULL) {
text = sub_ele->Attribute("ip");
if (text)
WorldIP=text;
text = sub_ele->Attribute("port");
if (text)
WorldTCPPort=atoi(text);
text = sub_ele->Attribute("telnet");
if (text && !strcasecmp(text,"enabled"))
TelnetEnabled=true;
}
// Get the <http> element
sub_ele = ele->FirstChildElement("http");
if(sub_ele != NULL) {
// text = sub_ele->Attribute("ip");
// if (text)
// WorldIP=text;
text = sub_ele->Attribute("mimefile");
if (text)
WorldHTTPMimeFile=text;
text = sub_ele->Attribute("port");
if (text)
WorldHTTPPort=atoi(text);
text = sub_ele->Attribute("enabled");
if (text && !strcasecmp(text,"true"))
WorldHTTPEnabled=true;
}
}
void EQEmuConfig::do_chatserver(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
ChatHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
ChatPort=atoi(text);
}
void EQEmuConfig::do_mailserver(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
MailHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
MailPort=atoi(text);
}
void EQEmuConfig::do_database(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"host",true);
if (text)
DatabaseHost=text;
text=ParseTextBlock(ele,"port",true);
if (text)
DatabasePort=atoi(text);
text=ParseTextBlock(ele,"username",true);
if (text)
DatabaseUsername=text;
text=ParseTextBlock(ele,"password",true);
if (text)
DatabasePassword=text;
text=ParseTextBlock(ele,"db",true);
if (text)
DatabaseDB=text;
}
void EQEmuConfig::do_zones(TiXmlElement *ele) {
const char *text;
TiXmlElement *sub_ele;
// TiXmlNode *node,*sub_node;
text=ParseTextBlock(ele,"defaultstatus",true);
if (text)
DefaultStatus=atoi(text);
// Get the <ports> element
sub_ele = ele->FirstChildElement("ports");
if(sub_ele != NULL) {
text = sub_ele->Attribute("low");
if (text)
ZonePortLow=atoi(text);;
text = sub_ele->Attribute("high");
if (text)
ZonePortHigh=atoi(text);
}
/* node = ele->FirstChild("start");
if (node) {
string s_static="static";
string s_dynamic="dynamic";
sub_node=NULL;
while( (sub_node = node->IterateChildren( sub_node )) ) {
if(sub_node->Type() != TiXmlNode::ELEMENT)
continue; //skip crap we dont care about
TiXmlElement *sub_ele = (TiXmlElement *) sub_node;
if (s_static == sub_ele->Value()) {
const char *zone = MakeLowerString(sub_ele->Attribute("zone"));
const char *port = sub_ele->Attribute("port");
if (zone) {
StaticZones[zone] = (port) ? atoi(port) : 0;
}
} else if (s_dynamic == sub_ele->Value()) {
const char *count = sub_ele->Attribute("count");
if (count) {
DynamicCount=atoi(count);
}
}
}
}*/
}
void EQEmuConfig::do_files(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"spells",true);
if (text)
SpellsFile=text;
text=ParseTextBlock(ele,"opcodes",true);
if (text)
OpCodesFile=text;
text=ParseTextBlock(ele,"logsettings",true);
if (text)
LogSettingsFile=text;
text=ParseTextBlock(ele,"eqtime",true);
if (text)
EQTimeFile=text;
}
void EQEmuConfig::do_directories(TiXmlElement *ele) {
const char *text;
text=ParseTextBlock(ele,"maps",true);
if (text)
MapDir=text;
text=ParseTextBlock(ele,"quests",true);
if (text)
QuestDir=text;
text=ParseTextBlock(ele,"plugins",true);
if (text)
PluginDir=text;
}
void EQEmuConfig::do_launcher(TiXmlElement *ele) {
const char *text;
TiXmlElement *sub_ele;
text=ParseTextBlock(ele,"logprefix",true);
if (text)
LogPrefix = text;
text=ParseTextBlock(ele,"logsuffix",true);
if (text)
LogSuffix = text;
// Get the <exe> element
text = ParseTextBlock(ele,"exe",true);
if (text)
ZoneExe = text;
// Get the <timers> element
sub_ele = ele->FirstChildElement("timers");
if(sub_ele != NULL) {
text = sub_ele->Attribute("restart");
if (text)
RestartWait = atoi(text);
text = sub_ele->Attribute("reterminate");
if (text)
TerminateWait = atoi(text);
text = sub_ele->Attribute("initial");
if (text)
InitialBootWait = atoi(text);
text = sub_ele->Attribute("interval");
if (text)
ZoneBootInterval = atoi(text);
}
}
string EQEmuConfig::GetByName(const string &var_name) const {
if(var_name == "ShortName")
return(ShortName);
if(var_name == "LongName")
return(LongName);
if(var_name == "WorldAddress")
return(WorldAddress);
if(var_name == "LoginHost")
return(LoginHost);
if(var_name == "LoginAccount")
return(LoginAccount);
if(var_name == "LoginPassword")
return(LoginPassword);
if(var_name == "LoginPort")
return(itoa(LoginPort));
#ifdef DUAL_SERVER
if(var_name == "LoginHost2")
return(LoginHost2);
if(var_name == "LoginAccount2")
return(LoginAccount2);
if(var_name == "LoginPassword2")
return(LoginPassword2);
if(var_name == "LoginPort2")
return(itoa(LoginPort2));
#endif
if(var_name == "Locked")
return(Locked?"true":"false");
if(var_name == "WorldTCPPort")
return(itoa(WorldTCPPort));
if(var_name == "WorldIP")
return(WorldIP);
if(var_name == "TelnetEnabled")
return(TelnetEnabled?"true":"false");
if(var_name == "WorldHTTPPort")
return(itoa(WorldHTTPPort));
if(var_name == "WorldHTTPMimeFile")
return(WorldHTTPMimeFile);
if(var_name == "WorldHTTPEnabled")
return(WorldHTTPEnabled?"true":"false");
if(var_name == "ChatHost")
return(ChatHost);
if(var_name == "ChatPort")
return(itoa(ChatPort));
if(var_name == "MailHost")
return(MailHost);
if(var_name == "MailPort")
return(itoa(MailPort));
if(var_name == "DatabaseHost")
return(DatabaseHost);
if(var_name == "DatabaseUsername")
return(DatabaseUsername);
if(var_name == "DatabasePassword")
return(DatabasePassword);
if(var_name == "DatabaseDB")
return(DatabaseDB);
if(var_name == "DatabasePort")
return(itoa(DatabasePort));
if(var_name == "SpellsFile")
return(SpellsFile);
if(var_name == "OpCodesFile")
return(OpCodesFile);
if(var_name == "EQTimeFile")
return(EQTimeFile);
if(var_name == "LogSettingsFile")
return(LogSettingsFile);
if(var_name == "MapDir")
return(MapDir);
if(var_name == "QuestDir")
return(QuestDir);
if(var_name == "PluginDir")
return(PluginDir);
if(var_name == "LogPrefix")
return(LogPrefix);
if(var_name == "LogSuffix")
return(LogSuffix);
if(var_name == "ZoneExe")
return(ZoneExe);
if(var_name == "ZonePortLow")
return(itoa(ZonePortLow));
if(var_name == "ZonePortHigh")
return(itoa(ZonePortHigh));
if(var_name == "DefaultStatus")
return(itoa(DefaultStatus));
// if(var_name == "DynamicCount")
// return(itoa(DynamicCount));
return("");
}
void EQEmuConfig::Dump() const
{
cout << "ShortName = " << ShortName << endl;
cout << "LongName = " << LongName << endl;
cout << "WorldAddress = " << WorldAddress << endl;
cout << "LoginHost = " << LoginHost << endl;
cout << "LoginAccount = " << LoginAccount << endl;
cout << "LoginPassword = " << LoginPassword << endl;
cout << "LoginPort = " << LoginPort << endl;
#ifdef DUAL_SERVER
cout << "LoginHost2 = " << LoginHost2 << endl;
cout << "LoginAccount2 = " << LoginAccount2 << endl;
cout << "LoginPassword2 = " << LoginPassword2 << endl;
cout << "LoginPort2 = " << LoginPort2 << endl;
#endif
cout << "Locked = " << Locked << endl;
cout << "WorldTCPPort = " << WorldTCPPort << endl;
cout << "WorldIP = " << WorldIP << endl;
cout << "TelnetEnabled = " << TelnetEnabled << endl;
cout << "WorldHTTPPort = " << WorldHTTPPort << endl;
cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << endl;
cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << endl;
cout << "ChatHost = " << ChatHost << endl;
cout << "ChatPort = " << ChatPort << endl;
cout << "MailHost = " << MailHost << endl;
cout << "MailPort = " << MailPort << endl;
cout << "DatabaseHost = " << DatabaseHost << endl;
cout << "DatabaseUsername = " << DatabaseUsername << endl;
cout << "DatabasePassword = " << DatabasePassword << endl;
cout << "DatabaseDB = " << DatabaseDB << endl;
cout << "DatabasePort = " << DatabasePort << endl;
cout << "SpellsFile = " << SpellsFile << endl;
cout << "OpCodesFile = " << OpCodesFile << endl;
cout << "EQTimeFile = " << EQTimeFile << endl;
cout << "LogSettingsFile = " << LogSettingsFile << endl;
cout << "MapDir = " << MapDir << endl;
cout << "QuestDir = " << QuestDir << endl;
cout << "PluginDir = " << PluginDir << endl;
cout << "ZonePortLow = " << ZonePortLow << endl;
cout << "ZonePortHigh = " << ZonePortHigh << endl;
cout << "DefaultStatus = " << (int)DefaultStatus << endl;
// cout << "DynamicCount = " << DynamicCount << endl;
}
EqEmuConfig.h
Code:
#ifndef __EQEmuConfig_H
#define __EQEmuConfig_H
#include "XMLParser.h"
class EQEmuConfig : public XMLParser {
public:
virtual string GetByName(const string &var_name) const;
// From <world/>
string ShortName;
string LongName;
string WorldAddress;
string LocalAddress;
string LoginHost;
string LoginAccount;
string LoginPassword;
uint16 LoginPort;
#ifdef DUAL_SERVER
string LoginHost2;
string LoginAccount2;
string LoginPassword2;
uint16 LoginPort2;
#endif
bool Locked;
uint16 WorldTCPPort;
string WorldIP;
bool TelnetEnabled;
sint32 MaxClients;
bool WorldHTTPEnabled;
uint16 WorldHTTPPort;
string WorldHTTPMimeFile;
string SharedKey;
// From <chatserver/>
string ChatHost;
uint16 ChatPort;
// From <mailserver/>
string MailHost;
uint16 MailPort;
// From <database/>
string DatabaseHost;
string DatabaseUsername;
string DatabasePassword;
string DatabaseDB;
uint16 DatabasePort;
// From <files/>
string SpellsFile;
string OpCodesFile;
string EQTimeFile;
string LogSettingsFile;
// From <directories/>
string MapDir;
string QuestDir;
string PluginDir;
// From <launcher/>
string LogPrefix;
string LogSuffix;
string ZoneExe;
uint32 RestartWait;
uint32 TerminateWait;
uint32 InitialBootWait;
uint32 ZoneBootInterval;
// From <zones/>
uint16 ZonePortLow;
uint16 ZonePortHigh;
uint8 DefaultStatus;
// uint16 DynamicCount;
// map<string,uint16> StaticZones;
protected:
static EQEmuConfig *_config;
static string ConfigFile;
#define ELEMENT(name) \
void do_##name(TiXmlElement *ele);
#include "EQEmuConfig_elements.h"
EQEmuConfig() {
// import the needed handler prototypes
#define ELEMENT(name) \
Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
#include "EQEmuConfig_elements.h"
// Set sane defaults
// Login server
LoginHost="eqemulator.net";
LoginPort=5998;
#ifdef DUAL_SERVER
LoginHost2="eqemulator.net2";
LoginPort2=5999;
#endif
// World
Locked=false;
WorldTCPPort=9000;
TelnetEnabled=false;
WorldHTTPEnabled=false;
WorldHTTPPort=9080;
WorldHTTPMimeFile="mime.types";
SharedKey = ""; //blank disables authentication
// Mail
ChatHost="eqchat.eqemulator.net";
ChatPort=7778;
// Mail
MailHost="eqmail.eqemulator.net";
MailPort=7779;
// Mysql
DatabaseHost="localhost";
DatabasePort=3306;
DatabaseUsername="eq";
DatabasePassword="eq";
DatabaseDB="eq";
// Files
SpellsFile="spells_us.txt";
OpCodesFile="opcodes.conf";
EQTimeFile="eqtime.cfg";
LogSettingsFile="log.ini";
// Dirs
MapDir="Maps";
QuestDir="quests";
PluginDir="plugins";
// Launcher
LogPrefix = "logs/zone-";
LogSuffix = ".log";
RestartWait = 10000; //milliseconds
TerminateWait = 10000; //milliseconds
InitialBootWait = 20000; //milliseconds
ZoneBootInterval = 2000; //milliseconds
#ifdef WIN32
ZoneExe = "zone.exe";
#else
ZoneExe = "./zone";
#endif
// Zones
ZonePortLow=7000;
ZonePortHigh=7999;
DefaultStatus=0;
// For where zones need to connect to.
WorldIP="127.0.0.1";
// Dynamics to start
//DynamicCount=5;
MaxClients=-1;
}
virtual ~EQEmuConfig() {}
public:
// Produce a const singleton
static const EQEmuConfig *get() {
if (_config == NULL)
LoadConfig();
return(_config);
}
// Allow the use to set the conf file to be used.
static void SetConfigFile(string file) { EQEmuConfig::ConfigFile = file; }
// Load the config
static bool LoadConfig() {
if (_config != NULL)
delete _config;
_config=new EQEmuConfig;
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
}
void Dump() const;
};
#endif
TCPConnection.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include "TCPConnection.h"
#include "../common/servertalk.h"
#include "../common/timer.h"
#include "../common/packet_dump.h"
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#define MSG_NOSIGNAL 0
#endif
#ifdef WIN32
InitWinsock winsock;
#endif
#define LOOP_GRANULARITY 3 //# of ms between checking our socket/queues
#define TCPN_DEBUG 0
#define TCPN_DEBUG_Console 0
#define TCPN_DEBUG_Memory 0
#define TCPN_LOG_RAW_DATA_OUT 0 //1 = info, 2 = length limited dump, 3 = full dump
#define TCPN_LOG_RAW_DATA_IN 0 //1 = info, 2 = length limited dump, 3 = full dump
#ifdef DUAL_SERVER
#include "../world/LoginServer.h"
#endif
//client version
TCPConnection::TCPConnection()
: ConnectionType(Outgoing),
connection_socket(0),
id(0),
rIP(0),
rPort(0)
{
pState = TCPS_Ready;
pFree = false;
pEcho = false;
recvbuf = NULL;
sendbuf = NULL;
pRunLoop = false;
charAsyncConnect = 0;
pAsyncConnect = false;
m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
cout << "Constructor #2 on outgoing TCP# " << GetID() << endl;
#endif
}
//server version
TCPConnection::TCPConnection(int32 ID, SOCKET in_socket, int32 irIP, int16 irPort)
: ConnectionType(Incomming),
connection_socket(in_socket),
id(ID),
rIP(irIP),
rPort(irPort)
{
pState = TCPS_Connected;
pFree = false;
pEcho = false;
recvbuf = NULL;
sendbuf = NULL;
pRunLoop = false;
charAsyncConnect = 0;
pAsyncConnect = false;
m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
cout << "Constructor #2 on incoming TCP# " << GetID() << endl;
#endif
}
TCPConnection::~TCPConnection() {
FinishDisconnect();
ClearBuffers();
if (ConnectionType == Outgoing) {
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
MLoopRunning.lock();
MLoopRunning.unlock();
#if TCPN_DEBUG_Memory >= 6
cout << "Deconstructor on outgoing TCP# " << GetID() << endl;
#endif
}
#if TCPN_DEBUG_Memory >= 5
else {
cout << "Deconstructor on incomming TCP# " << GetID() << endl;
}
#endif
safe_delete_array(recvbuf);
safe_delete_array(sendbuf);
safe_delete_array(charAsyncConnect);
}
void TCPConnection::SetState(State_t in_state) {
MState.lock();
pState = in_state;
MState.unlock();
}
TCPConnection::State_t TCPConnection::GetState() const {
State_t ret;
MState.lock();
ret = pState;
MState.unlock();
return ret;
}
bool TCPConnection::GetSockName(char *host, uint16 *port)
{
bool result=false;
LockMutex lock(&MState);
if (!Connected())
return false;
struct sockaddr_in local;
#ifdef WIN32
int addrlen;
#else
#ifdef FREEBSD
socklen_t addrlen;
#else
size_t addrlen;
#endif
#endif
addrlen=sizeof(struct sockaddr_in);
#ifdef WIN32
if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
#else
if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
#endif
unsigned long ip=local.sin_addr.s_addr;
sprintf(host,"%d.%d.%d.%d",
*(unsigned char *)&ip,
*((unsigned char *)&ip+1),
*((unsigned char *)&ip+2),
*((unsigned char *)&ip+3));
*port=ntohs(local.sin_port);
result=true;
}
return result;
}
void TCPConnection::Free() {
if (ConnectionType == Outgoing) {
ThrowError("TCPConnection::Free() called on an Outgoing connection");
}
#if TCPN_DEBUG_Memory >= 5
cout << "Free on TCP# " << GetID() << endl;
#endif
Disconnect();
pFree = true;
}
bool TCPConnection::Send(const uchar* data, sint32 size) {
if (!Connected())
return false;
if (!size)
return true;
ServerSendQueuePushEnd(data, size);
return true;
}
void TCPConnection::ServerSendQueuePushEnd(const uchar* data, sint32 size) {
MSendQueue.lock();
if (sendbuf == NULL) {
sendbuf = new uchar[size];
sendbuf_size = size;
sendbuf_used = 0;
}
else if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size + 1024;
uchar* tmp = new uchar[sendbuf_size];
memcpy(tmp, sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(&sendbuf[sendbuf_used], data, size);
sendbuf_used += size;
MSendQueue.unlock();
}
void TCPConnection::ServerSendQueuePushEnd(uchar** data, sint32 size) {
MSendQueue.lock();
if (sendbuf == 0) {
sendbuf = *data;
sendbuf_size = size;
sendbuf_used = size;
MSendQueue.unlock();
*data = 0;
return;
}
if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size;
uchar* tmp = new uchar[sendbuf_size];
memcpy(tmp, sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(&sendbuf[sendbuf_used], *data, size);
sendbuf_used += size;
MSendQueue.unlock();
safe_delete_array(*data);
}
void TCPConnection::ServerSendQueuePushFront(uchar* data, sint32 size) {
MSendQueue.lock();
if (sendbuf == 0) {
sendbuf = new uchar[size];
sendbuf_size = size;
sendbuf_used = 0;
}
else if (size > (sendbuf_size - sendbuf_used)) {
sendbuf_size += size;
uchar* tmp = new uchar[sendbuf_size];
memcpy(&tmp[size], sendbuf, sendbuf_used);
safe_delete_array(sendbuf);
sendbuf = tmp;
}
memcpy(sendbuf, data, size);
sendbuf_used += size;
MSendQueue.unlock();
}
bool TCPConnection::ServerSendQueuePop(uchar** data, sint32* size) {
bool ret;
if (!MSendQueue.trylock())
return false;
if (sendbuf) {
*data = sendbuf;
*size = sendbuf_used;
sendbuf = 0;
ret = true;
}
else {
ret = false;
}
MSendQueue.unlock();
return ret;
}
bool TCPConnection::ServerSendQueuePopForce(uchar** data, sint32* size) {
bool ret;
MSendQueue.lock();
if (sendbuf) {
*data = sendbuf;
*size = sendbuf_used;
sendbuf = 0;
ret = true;
}
else {
ret = false;
}
MSendQueue.unlock();
return ret;
}
char* TCPConnection::PopLine() {
char* ret;
if (!MLineOutQueue.trylock())
return 0;
ret = (char*) LineOutQueue.pop();
MLineOutQueue.unlock();
return ret;
}
bool TCPConnection::LineOutQueuePush(char* line) {
MLineOutQueue.lock();
LineOutQueue.push(line);
MLineOutQueue.unlock();
return(false);
}
void TCPConnection::FinishDisconnect() {
MState.lock();
if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
bool sent_something = false;
SendData(sent_something);
}
pState = TCPS_Closing;
shutdown(connection_socket, 0x01);
shutdown(connection_socket, 0x00);
#ifdef WIN32
closesocket(connection_socket);
#else
close(connection_socket);
#endif
connection_socket = 0;
rIP = 0;
rPort = 0;
ClearBuffers();
}
pState = TCPS_Disconnected;
MState.unlock();
}
void TCPConnection::Disconnect() {
MState.lock();
if(pState == TCPS_Connected || pState == TCPS_Connecting) {
pState = TCPS_Disconnecting;
}
MState.unlock();
}
bool TCPConnection::GetAsyncConnect() {
bool ret;
MAsyncConnect.lock();
ret = pAsyncConnect;
MAsyncConnect.unlock();
return ret;
}
bool TCPConnection::SetAsyncConnect(bool iValue) {
bool ret;
MAsyncConnect.lock();
ret = pAsyncConnect;
pAsyncConnect = iValue;
MAsyncConnect.unlock();
return ret;
}
bool TCPConnection::ConnectReady() const {
State_t s = GetState();
if (s != TCPS_Ready && s != TCPS_Disconnected)
return(false);
return(ConnectionType == Outgoing);
}
void TCPConnection::AsyncConnect(const char* irAddress, int16 irPort) {
safe_delete_array(charAsyncConnect);
charAsyncConnect = new char[strlen(irAddress) + 1];
strcpy(charAsyncConnect, irAddress);
AsyncConnect((int32) 0, irPort);
}
void TCPConnection::AsyncConnect(int32 irIP, int16 irPort) {
if (ConnectionType != Outgoing) {
// If this code runs, we got serious problems
// Crash and burn.
ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!");
return;
}
if(!ConnectReady()) {
#if TCPN_DEBUG > 0
printf("Trying to do async connect in invalid state %s\n", GetState());
#endif
return;
}
MAsyncConnect.lock();
if (pAsyncConnect) {
MAsyncConnect.unlock();
#if TCPN_DEBUG > 0
printf("Trying to do async connect when already doing one.\n");
#endif
return;
}
#if TCPN_DEBUG > 0
printf("Start async connect.\n");
#endif
pAsyncConnect = true;
if(irIP != 0)
safe_delete_array(charAsyncConnect);
rIP = irIP;
rPort = irPort;
MAsyncConnect.unlock();
if (!pRunLoop) {
pRunLoop = true;
#ifdef WIN32
_beginthread(TCPConnectionLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
}
return;
}
bool TCPConnection::Connect(const char* irAddress, int16 irPort, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
int32 tmpIP = ResolveIP(irAddress);
if (!tmpIP) {
if (errbuf) {
#ifdef WIN32
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
#else
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
#endif
}
return false;
}
return ConnectIP(tmpIP, irPort, errbuf);
}
bool TCPConnection::ConnectIP(int32 in_ip, int16 in_port, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (ConnectionType != Outgoing) {
// If this code runs, we got serious problems
// Crash and burn.
ThrowError("TCPConnection::Connect() call on a Incomming connection object!");
return false;
}
MState.lock();
if (ConnectReady()) {
pState = TCPS_Connecting;
} else {
MState.unlock();
SetAsyncConnect(false);
return false;
}
MState.unlock();
if (!pRunLoop) {
pRunLoop = true;
#ifdef WIN32
_beginthread(TCPConnectionLoop, 0, this);
#else
pthread_t thread;
pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
}
connection_socket = INVALID_SOCKET;
struct sockaddr_in server_sin;
// struct in_addr in;
if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
#ifdef WIN32
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
#else
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
#endif
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
server_sin.sin_family = AF_INET;
server_sin.sin_addr.s_addr = in_ip;
server_sin.sin_port = htons(in_port);
// Establish a connection to the server socket.
#ifdef WIN32
if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
closesocket(connection_socket);
connection_socket = 0;
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
#else
if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
close(connection_socket);
connection_socket = 0;
SetState(TCPS_Ready);
SetAsyncConnect(false);
return false;
}
#endif
int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef WIN32
unsigned long nonblocking = 1;
ioctlsocket(connection_socket, FIONBIO, &nonblocking);
#else
fcntl(connection_socket, F_SETFL, O_NONBLOCK);
#endif
SetEcho(false);
ClearBuffers();
rIP = in_ip;
rPort = in_port;
SetState(TCPS_Connected);
SetAsyncConnect(false);
return true;
}
void TCPConnection::ClearBuffers() {
LockMutex lock1(&MSendQueue);
LockMutex lock3(&MRunLoop);
LockMutex lock4(&MState);
safe_delete_array(recvbuf);
safe_delete_array(sendbuf);
char* line = 0;
while ((line = LineOutQueue.pop()))
safe_delete_array(line);
}
bool TCPConnection::CheckNetActive() {
MState.lock();
if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
MState.unlock();
return true;
}
MState.unlock();
return false;
}
/* This is always called from an IO thread. Either the server socket's thread, or a
* special thread we create when we make an outbound connection. */
bool TCPConnection::Process() {
char errbuf[TCPConnection_ErrorBufferSize];
switch(GetState()) {
case TCPS_Ready:
case TCPS_Connecting:
if (ConnectionType == Outgoing) {
if (GetAsyncConnect()) {
if (charAsyncConnect)
rIP = ResolveIP(charAsyncConnect);
ConnectIP(rIP, rPort);
}
}
return(true);
case TCPS_Connected:
// only receive data in the connected state, no others...
if (!RecvData(errbuf)) {
struct in_addr in;
in.s_addr = GetrIP();
//cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
return false;
}
/* we break to do the send */
break;
case TCPS_Disconnecting: {
//waiting for any sending data to go out...
MSendQueue.lock();
if(sendbuf) {
if(sendbuf_used > 0) {
//something left to send, keep processing...
MSendQueue.unlock();
break;
}
//else, send buffer is empty.
safe_delete_array(sendbuf);
} //else, no send buffer, we are done.
MSendQueue.unlock();
}
/* Fallthrough */
case TCPS_Disconnected:
FinishDisconnect();
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
// SetState(TCPS_Ready); //reset the state in case they want to use it again...
return(false);
case TCPS_Closing:
//I dont understand this state...
case TCPS_Error:
MRunLoop.lock();
pRunLoop = false;
MRunLoop.unlock();
return(false);
}
/* we get here in connected or disconnecting with more data to send */
bool sent_something = false;
if (!SendData(sent_something, errbuf)) {
struct in_addr in;
in.s_addr = GetrIP();
cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
return false;
}
return true;
}
bool TCPConnection::RecvData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (!Connected()) {
return false;
}
int status = 0;
if (recvbuf == 0) {
recvbuf = new uchar[5120];
recvbuf_size = 5120;
recvbuf_used = 0;
recvbuf_echo = 0;
}
else if ((recvbuf_size - recvbuf_used) < 2048) {
uchar* tmpbuf = new uchar[recvbuf_size + 5120];
memcpy(tmpbuf, recvbuf, recvbuf_used);
recvbuf_size += 5120;
safe_delete_array(recvbuf);
recvbuf = tmpbuf;
if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
return false;
}
}
status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);
if (status >= 1) {
#if TCPN_LOG_RAW_DATA_IN >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
cout << endl;
#if TCPN_LOG_RAW_DATA_IN == 2
sint32 tmp = status;
if (tmp > 32)
tmp = 32;
DumpPacket(&recvbuf[recvbuf_used], status);
#elif TCPN_LOG_RAW_DATA_IN >= 3
DumpPacket(&recvbuf[recvbuf_used], status);
#endif
#endif
recvbuf_used += status;
if (!ProcessReceivedData(errbuf))
return false;
}
else if (status == SOCKET_ERROR) {
#ifdef WIN32
if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
return false;
}
#else
if (!(errno == EWOULDBLOCK)) {
if (errbuf)
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
return false;
}
#endif
} else if (status == 0) {
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
return false;
}
return true;
}
bool TCPConnection::GetEcho() {
bool ret;
ret = pEcho;
return ret;
}
void TCPConnection::SetEcho(bool iValue) {
pEcho = iValue;
}
bool TCPConnection::ProcessReceivedData(char* errbuf) {
if (errbuf)
errbuf[0] = 0;
if (!recvbuf)
return true;
#if TCPN_DEBUG_Console >= 4
if (recvbuf_used) {
cout << "Starting Processing: recvbuf=" << recvbuf_used << endl;
DumpPacket(recvbuf, recvbuf_used);
}
#endif
for (int i=0; i < recvbuf_used; i++) {
if (GetEcho() && i >= recvbuf_echo) {
Send(&recvbuf[i], 1);
recvbuf_echo = i + 1;
}
switch(recvbuf[i]) {
case 0: { // 0 is the code for clear buffer
if (i==0) {
recvbuf_used--;
recvbuf_echo--;
memmove(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
if (i == recvbuf_used) {
safe_delete_array(recvbuf);
i = -1;
}
else {
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
recvbuf_used -= i + 1;
recvbuf_echo -= i + 1;
safe_delete_array(tmpdel);
i = -1;
}
}
#if TCPN_DEBUG_Console >= 5
cout << "Removed 0x00" << endl;
if (recvbuf_used) {
cout << "recvbuf left: " << recvbuf_used << endl;
DumpPacket(recvbuf, recvbuf_used);
}
else
cout << "recbuf left: None" << endl;
#endif
m_previousLineEnd = false;
break;
}
case 10:
case 13: // newline marker
{
char *line = NULL;
if (i==0) { // empty line
if(!m_previousLineEnd) {
//char right before this was NOT a CR, report the empty line.
line = new char[1];
line[0] = '\0';
m_previousLineEnd = true;
} else {
m_previousLineEnd = false;
}
recvbuf_used--;
recvbuf_echo--;
memcpy(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
line = new char[i+1];
memset(line, 0, i+1);
memcpy(line, recvbuf, i);
#if TCPN_DEBUG_Console >= 3
cout << "Line Out: " << endl;
DumpPacket((uchar*) line, i);
#endif
//line[i] = 0;
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
recvbuf_used -= i+1;
recvbuf_echo -= i+1;
memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
#if TCPN_DEBUG_Console >= 5
cout << "i+1=" << i+1 << endl;
if (recvbuf_used) {
cout << "recvbuf left: " << recvbuf_used << endl;
DumpPacket(recvbuf, recvbuf_used);
}
else
cout << "recbuf left: None" << endl;
#endif
safe_delete_array(tmpdel);
i = -1;
m_previousLineEnd = true;
}
if(line != NULL) {
bool finish_proc = false;
finish_proc = LineOutQueuePush(line);
if(finish_proc)
return(true); //break early as requested by LineOutQueuePush
}
break;
}
case 8: // backspace
{
if (i==0) { // nothin to backspace
recvbuf_used--;
recvbuf_echo--;
memmove(recvbuf, &recvbuf[1], recvbuf_used);
i = -1;
} else {
uchar* tmpdel = recvbuf;
recvbuf = new uchar[recvbuf_size];
memcpy(recvbuf, tmpdel, i-1);
memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
recvbuf_used -= 2;
recvbuf_echo -= 2;
safe_delete_array(tmpdel);
i -= 2;
}
break;
m_previousLineEnd = false;
}
default:
m_previousLineEnd = false;
}
}
if (recvbuf_used < 0)
safe_delete_array(recvbuf);
return true;
}
bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
if (errbuf)
errbuf[0] = 0;
/************ Get first send packet on queue and send it! ************/
uchar* data = 0;
sint32 size = 0;
int status = 0;
if (ServerSendQueuePop(&data, &size)) {
#ifdef WIN32
status = send(connection_socket, (const char *) data, size, 0);
#else
status = send(connection_socket, data, size, MSG_NOSIGNAL);
if(errno==EPIPE) status = SOCKET_ERROR;
#endif
if (status >= 1) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
cout << endl;
#if TCPN_LOG_RAW_DATA_OUT == 2
sint32 tmp = status;
if (tmp > 32)
tmp = 32;
DumpPacket(data, status);
#elif TCPN_LOG_RAW_DATA_OUT >= 3
DumpPacket(data, status);
#endif
#endif
sent_something = true;
if (status < (signed)size) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
struct in_addr in;
in.s_addr = GetrIP();
CoutTimestamp(true);
cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
cout << endl;
#endif
// If there's network congestion, the number of bytes sent can be less than
// what we tried to give it... Push the extra back on the queue for later
ServerSendQueuePushFront(&data[status], size - status);
}
else if (status > (signed)size) {
ThrowError("TCPConnection::SendData(): WTF! status > size");
return false;
}
// else if (status == size) {}
}
else {
ServerSendQueuePushFront(data, size);
}
safe_delete_array(data);
if (status == SOCKET_ERROR) {
#ifdef WIN32
if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EWOULDBLOCK)
#endif
{
if (errbuf) {
#ifdef WIN32
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
#else
snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
#endif
}
//if we get an error while disconnecting, just jump to disconnected
MState.lock();
if(pState == TCPS_Disconnecting)
pState = TCPS_Disconnected;
MState.unlock();
return false;
}
}
}
return true;
}
ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
#ifdef WIN32
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
if (tmp == 0) {
ThrowError("TCPConnectionLoop(): tmp = 0!");
THREAD_RETURN(NULL);
}
TCPConnection* tcpc = (TCPConnection*) tmp;
#ifndef WIN32
_log(COMMON__THREADS, "Starting TCPConnectionLoop with thread ID %d", pthread_self());
#endif
tcpc->MLoopRunning.lock();
while (tcpc->RunLoop()) {
Sleep(LOOP_GRANULARITY);
if (!tcpc->ConnectReady()) {
_CP(TCPConnectionLoop);
if (!tcpc->Process()) {
//the processing loop has detecting an error..
//we want to drop the link immediately, so we clear buffers too.
tcpc->ClearBuffers();
tcpc->Disconnect();
}
#ifdef DUAL_SERVER
Sleep(100);
#else
Sleep(1);
#endif
}
else if (tcpc->GetAsyncConnect()) {
_CP(TCPConnectionLoop);
if (tcpc->charAsyncConnect)
tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
else
tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
tcpc->SetAsyncConnect(false);
}
else
Sleep(10); //nothing to do.
}
tcpc->MLoopRunning.unlock();
#ifndef WIN32
#ifdef DUAL_SERVER
_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d, Did you loose a server connection?", pthread_self()); //Angelox
#else
_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d", pthread_self());
#endif
#endif
THREAD_RETURN(NULL);
#ifdef DUAL_SERVER
_log(WORLD__CONSOLE,"Login Server Reconnect Attempt...");
InitLoginServer();
/* #ifdef WIN32
_beginthread(AutoInitLoginServer, 0, NULL);
#else
pthread_t thread;
pthread_create(&thread, NULL, &AutoInitLoginServer, NULL);
#endif
RunLoops = true;
_log(WORLD__CONSOLE,"Login Server Reconnect Attempt..."); */
#endif
}
bool TCPConnection::RunLoop() {
bool ret;
MRunLoop.lock();
ret = pRunLoop;
MRunLoop.unlock();
return ret;
}
database.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include <map>
// Disgrace: for windows compile
#ifdef WIN32
#include <windows.h>
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include "unix.h"
#include <netinet/in.h>
#include <sys/time.h>
#endif
#ifdef EQBOTS
#include "../zone/botDatabase.h"
#endif //EQBOTS
#include "database.h"
#include "eq_packet_structs.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "extprofile.h"
/*#include "../common/classes.h"
#include "../common/races.h"
#include "../common/files.h"
#include "../common/EQEMuError.h"
#include "../common/packet_dump.h"
*/
extern Client client;
/*
This is the amount of time in seconds the client has to enter the zone
server after the world server, or inbetween zones when that is finished
*/
/*
Establish a connection to a mysql database with the supplied parameters
Added a very simple .ini file parser - Bounce
Modify to use for win32 & linux - misanthropicfiend
*/
Database::Database ()
{
DBInitVars();
}
/*
Establish a connection to a mysql database with the supplied parameters
*/
Database::Database(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
DBInitVars();
Connect(host, user, passwd, database, port);
}
bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
int32 errnum= 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf))
{
LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
HandleMysqlError(errnum);
return false;
}
else
{
LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
return true;
}
}
void Database::DBInitVars() {
max_zonename = 0;
zonename_array = 0;
varcache_array = 0;
varcache_max = 0;
varcache_lastupdate = 0;
}
void Database::HandleMysqlError(int32 errnum) {
/* switch(errnum) {
case 0:
break;
case 1045: // Access Denied
case 2001: {
AddEQEMuError(EQEMuError_Mysql_1405, true);
break;
}
case 2003: { // Unable to connect
AddEQEMuError(EQEMuError_Mysql_2003, true);
break;
}
case 2005: { // Unable to connect
AddEQEMuError(EQEMuError_Mysql_2005, true);
break;
}
case 2007: { // Unable to connect
AddEQEMuError(EQEMuError_Mysql_2007, true);
break;
}
}*/
}
/*
Close the connection to the database
*/
Database::~Database()
{
unsigned int x;
if (zonename_array) {
for (x=0; x<=max_zonename; x++) {
if (zonename_array[x])
safe_delete_array(zonename_array[x]);
}
safe_delete_array(zonename_array);
}
if (varcache_array) {
for (x=0; x<varcache_max; x++) {
safe_delete_array(varcache_array[x]);
}
safe_delete_array(varcache_array);
}
}
/*
Check if there is an account with name "name" and password "password"
Return the account id or zero if no account matches.
Zero will also be returned if there is a database error.
*/
int32 Database::CheckLogin(const char* name, const char* password, sint16* oStatus) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(strlen(name) >= 50 || strlen(password) >= 50)
return(0);
char tmpUN[100];
char tmpPW[100];
DoEscapeString(tmpUN, name, strlen(name));
DoEscapeString(tmpPW, password, strlen(password));
if (RunQuery(query, MakeAnyLenString(&query,
"SELECT id, status FROM account WHERE name='%s' AND password is not null "
"and length(password) > 0 and (password='%s' or password=MD5('%s'))",
tmpUN, tmpPW, tmpPW), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
int32 id = atoi(row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
mysql_free_result(result);
return id;
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else
{
cerr << "Error in CheckLogin query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return 0;
}
//Lieka: Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
bool Database::CheckBannedIPs(const char* loginIP)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
//cout << "Checking against Banned IPs table."<< endl; //Lieka: Debugging
if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%s'", loginIP), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
//cout << loginIP << " was present in the banned IPs table" << endl; //Lieka: Debugging
mysql_free_result(result);
return true;
}
else
{
//cout << loginIP << " was not present in the banned IPs table." << endl; //Lieka: Debugging
mysql_free_result(result);
return false;
}
mysql_free_result(result);
}
else
{
cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return true;
}
return true;
}
bool Database::AddBannedIP(char* bannedIP, const char* notes)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes), errbuf)) {
cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
//End Lieka Edit
bool Database::CheckGMIPs(const char* ip_address, int32 account_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM `gm_ips` WHERE `ip_address` = '%s' AND `account_id` = %i", ip_address, account_id), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
mysql_free_result(result);
return true;
} else {
mysql_free_result(result);
return false;
}
mysql_free_result(result);
} else {
safe_delete_array(query);
return false;
}
return false;
}
bool Database::AddGMIP(char* ip_address, char* name) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into `gm_ips` SET `ip_address` = '%s', `name` = '%s'", ip_address, name), errbuf)) {
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
void Database::LoginIP(int32 AccountID, const char* LoginIP)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO account_ip SET accid=%i, ip='%s' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()", AccountID, LoginIP), errbuf)) {
cerr << "Error in Log IP query '" << query << "' " << errbuf << endl;
}
safe_delete_array(query);
}
sint16 Database::CheckStatus(int32 account_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT status FROM account WHERE id='%i'", account_id), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
sint16 status = atoi(row[0]);
mysql_free_result(result);
return status;
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else
{
cerr << "Error in CheckStatus query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return 0;
}
#ifdef DUAL_SERVER
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id, int32 lsaccount_id2) {
#else
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id) {
#endif
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 querylen;
int32 last_insert_id;
MYSQL_RES *result;
// if (paccountid == 0 && LSID()>0) {
#ifdef DUAL_SERVER
RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", name), errbuf, &result);
if (mysql_num_rows(result) == 1) {
lsaccount_id2 = lsaccount_id;
safe_delete_array(query);
if (lsaccount_id > 4999999){
(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id=%i WHERE name='%s'AND lsaccount_id IS NULL;", lsaccount_id, name), errbuf, 0));
safe_delete_array(query);
}
else if (lsaccount_id < 5000000){
(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id2=%i WHERE name='%s'AND lsaccount_id2='0';", lsaccount_id2, name), errbuf, 0));
safe_delete_array(query);
}
safe_delete_array(query);
}
safe_delete_array(query);
if ((password) && (lsaccount_id > 4999999))
#else
if (password)
#endif
querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id=%i;",name,password,status, lsaccount_id);
#ifdef DUAL_SERVER
else if (lsaccount_id > 4999999)
querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#else
else
querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#endif
#ifdef DUAL_SERVER
lsaccount_id2 = lsaccount_id;
if ((password) && (lsaccount_id < 5000000))
querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id2=%i;",name,password,status, lsaccount_id2);
else if (lsaccount_id < 5000000)
querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id2=%i;",name, status, lsaccount_id2);
#endif //Dual Server
cerr << "Account Attempting to be created:" << name << " " << (sint16) status << endl;
if (!RunQuery(query, querylen, errbuf, 0, 0, &last_insert_id)) {
cerr << "Error in CreateAccount query, possible second account added,try again- '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return 0;
}
safe_delete_array(query);
if (last_insert_id == 0) {
cerr << "Error in CreateAccount query '" << query << "' " << errbuf << endl;
return 0;
}
return last_insert_id;
}
bool Database::DeleteAccount(const char* name) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
cerr << "Account Attempting to be deleted:" << name << endl;
if (RunQuery(query, MakeAnyLenString(&query, "DELETE FROM account WHERE name='%s';",name), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
if (affected_rows == 1) {
return true;
}
}
else {
cerr << "Error in DeleteAccount query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return false;
}
bool Database::SetLocalPassword(int32 accid, const char* password) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET password=MD5('%s') where id=%i;", password, accid), errbuf)) {
cerr << "Error in SetLocalPassword query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
bool Database::SetAccountStatus(const char* name, sint16 status) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
cout << "Account being GM Flagged:" << name << ", Level: " << (sint16) status << endl;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET status=%i WHERE name='%s';", status, name), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
return false;
}
safe_delete_array(query);
if (affected_rows == 0) {
cout << "Account: " << name << " does not exist, therefore it cannot be flagged\n";
return false;
}
return true;
}
//---------------------------------
//End of adventure database code.--
//---------------------------------
bool Database::ReserveName(int32 account_id, char* name)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into character_ SET account_id=%i, name='%s', profile=NULL", account_id, name), errbuf)) {
cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
/*
Delete the character with the name "name"
returns false on failure, true otherwise
*/
bool Database::DeleteCharacter(char *name)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query=0;
MYSQL_RES *result;
MYSQL_ROW row;
int charid, matches;
int32 affected_rows;
if(!name || !strlen(name))
{
printf("DeleteCharacter: request to delete without a name (empty char slot)\n");
return false;
}
// SCORPIOUS2K - get id from character_ before deleting record so we can clean up inventory and qglobal
#if DEBUG >= 5
printf("DeleteCharacter: Attempting to delete '%s'\n", name);
#endif
RunQuery(query, MakeAnyLenString(&query, "SELECT id from character_ WHERE name='%s'", name), errbuf, &result);
if (query)
{
safe_delete_array(query);
query = NULL;
}
matches = mysql_num_rows(result);
if(matches == 1)
{
row = mysql_fetch_row(result);
charid = atoi(row[0]);
#if DEBUG >= 5
printf("DeleteCharacter: found '%s' with char id: %d\n", name, charid);
#endif
}
else
{
printf("DeleteCharacter: error: got %d rows matching '%s'\n", matches, name);
if(result)
{
mysql_free_result(result);
result = NULL;
}
return false;
}
if(result)
{
mysql_free_result(result);
result = NULL;
}
#if DEBUG >= 5
printf("DeleteCharacter: deleting '%s' (id %d): ", name, charid);
printf(" quest_globals");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from quest_globals WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" character_tasks");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from character_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" character_activities");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from character_activities WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" character_enabledtasks");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from character_enabledtasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" completed_tasks");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from completed_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" friends");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from friends WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" ptimers");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from timers WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" inventory");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from inventory WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" guild_members");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM guild_members WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf(" _character");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE from character_ WHERE id='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
if(affected_rows != 1) // here we have to have a match or it's an error
{
LogFile->write(EQEMuLog::Error, "DeleteCharacter: error: delete operation affected %d rows\n", affected_rows);
return false;
}
#if DEBUG >= 5
printf(" keyring");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM keyring WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
#if DEBUG >= 5
printf("\n");
#endif
printf("DeleteCharacter: successfully deleted '%s' (id %d)\n", name, charid);
return true;
}
// Store new character information into the character_ and inventory tables
bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext)
{
_CP(Database_StoreCharacter);
char errbuf[MYSQL_ERRMSG_SIZE];
char query[256+sizeof(PlayerProfile_Struct)*2+sizeof(ExtendedProfile_Struct)*2+5];
char* end = query;
int32 affected_rows = 0;
int i;
int32 charid = 0;
char* charidquery = 0;
char* invquery = 0;
MYSQL_RES *result;
MYSQL_ROW row = 0;
char zone[50];
float x, y, z;
// memset(&playeraa, 0, sizeof(playeraa));
// get the char id (used in inventory inserts below)
if(!RunQuery
(
charidquery,
MakeAnyLenString
(
&charidquery,
"SELECT id FROM character_ where name='%s'",
pp->name
),
errbuf,
&result
)) {
LogFile->write(EQEMuLog::Error, "Error in char store id query: %s: %s", charidquery, errbuf);
return(false);
}
safe_delete_array(charidquery);
if(mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
if(row[0])
charid = atoi(row[0]);
}
if(!charid)
{
LogFile->write(EQEMuLog::Error, "StoreCharacter: no character id");
return false;
}
const char *zname = GetZoneName(pp->zone_id);
if(zname == NULL) {
//zone not in the DB, something to prevent crash...
strncpy(zone, "qeynos", 49);
pp->zone_id = 1;
} else
strncpy(zone, zname, 49);
x=pp->x;
y=pp->y;
z=pp->z;
// construct the character_ query
end += sprintf(end,
"UPDATE character_ SET timelaston=0, "
"zonename=\'%s\', x=%f, y=%f, z=%f, profile=\'",
zone, x, y, z
);
end += DoEscapeString(end, (char*)pp, sizeof(PlayerProfile_Struct));
end += sprintf(end, "\', extprofile=\'");
end += DoEscapeString(end, (char*)ext, sizeof(ExtendedProfile_Struct));
end += sprintf(end, "\' WHERE account_id=%d AND name='%s'",account_id, pp->name);
RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows);
if(!affected_rows)
{
LogFile->write(EQEMuLog::Error, "StoreCharacter query '%s' %s", query, errbuf);
return false;
}
affected_rows = 0;
// Doodman: Is this even used?
// now the inventory
for (i=0; i<=2270;)
{
const ItemInst* newinv = inv->GetItem((sint16)i);
if (newinv)
{
MakeAnyLenString
(
&invquery,
"INSERT INTO inventory SET "
"charid=%0u, slotid=%0d, itemid=%0u, charges=%0d, color=%0u",
charid, i, newinv->GetItem()->ID,
newinv->GetCharges(), newinv->GetColor()
);
RunQuery(invquery, strlen(invquery), errbuf, 0, &affected_rows);
if(!affected_rows)
{
LogFile->write(EQEMuLog::Error, "StoreCharacter inventory failed. Query '%s' %s", invquery, errbuf);
}
safe_delete_array(invquery);
#if EQDEBUG >= 9
else
{
LogFile->write(EQEMuLog::Debug, "StoreCharacter inventory succeeded. Query '%s' %s", invquery, errbuf);
}
#endif
}
if(i==30){ //end of standard inventory/cursor, jump to internals of bags/cursor
i = 251;
continue;
} else if(i==340){ //end of internals of bags/cursor, jump to bank slots
i = 2000;
continue;
} else if(i==2023){ //end of bank slots, jump to internals of bank bags
i = 2031;
continue;
}
i++;
}
return true;
}
//0=failure, otherwise returns the char ID for the given char name.
int32 Database::GetCharacterID(const char *name) {
int32 cid = 0;
if(GetAccountIDByChar(name, &cid) == 0)
return(0);
return(cid);
}
/*
This function returns the account_id that owns the character with
the name "name" or zero if no character with that name was found
Zero will also be returned if there is a database error.
*/
int32 Database::GetAccountIDByChar(const char* charname, int32* oCharID) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id, id FROM character_ WHERE name='%s'", charname), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
if (oCharID)
*oCharID = atoi(row[1]);
mysql_free_result(result);
return tmp;
}
mysql_free_result(result);
}
else {
cerr << "Error in GetAccountIDByChar query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return 0;
}
// Retrieve account_id for a given char_id
uint32 Database::GetAccountIDByChar(uint32 char_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 ret = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id FROM character_ WHERE id=%i", char_id), errbuf, &result)) {
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
ret = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
}
mysql_free_result(result);
}
else {
LogFile->write(EQEMuLog::Error, "Error in GetAccountIDByChar query '%s': %s", query, errbuf);
}
safe_delete_array(query);
return ret;
}
int32 Database::GetAccountIDByName(const char* accname, sint16* status, int32* lsid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
for (unsigned int i=0; i<strlen(accname); i++) {
if ((accname[i] < 'a' || accname[i] > 'z') &&
(accname[i] < 'A' || accname[i] > 'Z') &&
(accname[i] < '0' || accname[i] > '9'))
return 0;
}
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", accname), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
if (status)
*status = atoi(row[1]);
if (lsid) {
if (row[2])
*lsid = atoi(row[2]);
else
*lsid = 0;
}
mysql_free_result(result);
return tmp;
}
mysql_free_result(result);
}
else {
cerr << "Error in GetAccountIDByAcc query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return 0;
}
void Database::GetAccountName(int32 accountid, char* name, int32* oLSAccountID) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, lsaccount_id FROM account WHERE id='%i'", accountid), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
strcpy(name, row[0]);
if (row[1] && oLSAccountID) {
*oLSAccountID = atoi(row[1]);
}
}
mysql_free_result(result);
}
else {
safe_delete_array(query);
cerr << "Error in GetAccountName query '" << query << "' " << errbuf << endl;
}
}
void Database::GetCharName(int32 char_id, char* name) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM character_ WHERE id='%i'", char_id), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
strcpy(name, row[0]);
}
mysql_free_result(result);
}
else {
safe_delete_array(query);
cerr << "Error in GetCharName query '" << query << "' " << errbuf << endl;
}
}
bool Database::LoadVariables() {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, LoadVariables_MQ(&query), errbuf, &result)) {
safe_delete_array(query);
bool ret = LoadVariables_result(result);
mysql_free_result(result);
return ret;
}
else {
cerr << "Error in LoadVariables query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return false;
}
int32 Database::LoadVariables_MQ(char** query) {
// the read of this single variable should be atomic... this was causing strange problems
// LockMutex lock(&Mvarcache);
return MakeAnyLenString(query, "SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache_lastupdate);
}
bool Database::LoadVariables_result(MYSQL_RES* result) {
int32 i;
MYSQL_ROW row;
LockMutex lock(&Mvarcache);
if (mysql_num_rows(result) > 0) {
if (!varcache_array) {
varcache_max = mysql_num_rows(result);
varcache_array = new VarCache_Struct*[varcache_max];
for (i=0; i<varcache_max; i++)
varcache_array[i] = 0;
}
else {
int32 tmpnewmax = varcache_max + mysql_num_rows(result);
VarCache_Struct** tmp = new VarCache_Struct*[tmpnewmax];
for (i=0; i<tmpnewmax; i++)
tmp[i] = 0;
for (i=0; i<varcache_max; i++)
tmp[i] = varcache_array[i];
VarCache_Struct** tmpdel = varcache_array;
varcache_array = tmp;
varcache_max = tmpnewmax;
delete tmpdel;
}
while ((row = mysql_fetch_row(result))) {
varcache_lastupdate = atoi(row[2]);
for (i=0; i<varcache_max; i++) {
if (varcache_array[i]) {
if (strcasecmp(varcache_array[i]->varname, row[0]) == 0) {
delete varcache_array[i];
varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
strn0cpy(varcache_array[i]->varname, row[0], sizeof(varcache_array[i]->varname));
strcpy(varcache_array[i]->value, row[1]);
break;
}
}
else {
varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
strcpy(varcache_array[i]->varname, row[0]);
strcpy(varcache_array[i]->value, row[1]);
break;
}
}
}
int32 max_used = 0;
for (i=0; i<varcache_max; i++) {
if (varcache_array[i]) {
if (i > max_used)
max_used = i;
}
}
max_used++;
varcache_max = max_used;
}
return true;
}
// Gets variable from 'variables' table
bool Database::GetVariable(const char* varname, char* varvalue, int16 varvalue_len) {
varvalue[0] = '\0';
LockMutex lock(&Mvarcache);
if (strlen(varname) <= 1)
return false;
for (int32 i=0; i<varcache_max; i++) {
if (varcache_array[i]) {
if (strcasecmp(varcache_array[i]->varname, varname) == 0) {
snprintf(varvalue, varvalue_len, "%s", varcache_array[i]->value);
varvalue[varvalue_len-1] = 0;
return true;
}
}
else
return false;
}
return false;
}
bool Database::SetVariable(const char* varname_in, const char* varvalue_in) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
char *varname,*varvalue;
varname=(char *)malloc(strlen(varname_in)*2+1);
varvalue=(char *)malloc(strlen(varvalue_in)*2+1);
DoEscapeString(varname, varname_in, strlen(varname_in));
DoEscapeString(varvalue, varvalue_in, strlen(varvalue_in));
if (RunQuery(query, MakeAnyLenString(&query, "Update variables set value='%s' WHERE varname like '%s'", varvalue, varname), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
if (affected_rows == 1) {
LoadVariables(); // refresh cache
free(varname);
free(varvalue);
return true;
}
else {
if (RunQuery(query, MakeAnyLenString(&query, "Insert Into variables (varname, value) values ('%s', '%s')", varname, varvalue), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
if (affected_rows == 1) {
LoadVariables(); // refresh cache
free(varname);
free(varvalue);
return true;
}
}
}
}
else {
cerr << "Error in SetVariable query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
free(varname);
free(varvalue);
return false;
}
int32 Database::GetMiniLoginAccount(char* ip){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 retid = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM account WHERE minilogin_ip='%s'", ip), errbuf, &result)) {
safe_delete_array(query);
if ((row = mysql_fetch_row(result)))
retid = atoi(row[0]);
mysql_free_result(result);
}
else
{
cerr << "Error in GetMiniLoginAccount query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return retid;
}
// Pyro: Get zone starting points from DB
bool Database::GetSafePoints(const char* short_name, float* safe_x, float* safe_y, float* safe_z, sint16* minstatus, int8* minlevel, char *flag_needed, int8* canzone) { //Angelox4
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
// int buf_len = 256;
// int chars = -1;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query,
"SELECT safe_x, safe_y, safe_z, min_status, min_level, "
" flag_needed, canzone FROM zone " //Angelox4
" WHERE short_name='%s'", short_name), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
if (safe_x != 0)
*safe_x = atof(row[0]);
if (safe_y != 0)
*safe_y = atof(row[1]);
if (safe_z != 0)
*safe_z = atof(row[2]);
if (minstatus != 0)
*minstatus = atoi(row[3]);
if (minlevel != 0)
*minlevel = atoi(row[4]);
if (flag_needed != NULL)
strcpy(flag_needed, row[5]);
if (canzone != 0) //Angelox4
*canzone = atoi(row[6]); //Angelox4
mysql_free_result(result);
return true;
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetSafePoint query '" << query << "' " << errbuf << endl;
cerr << "If it errors, run the following querys:\n";
cerr << "ALTER TABLE `zone` CHANGE `minium_level` `min_level` TINYINT(3) UNSIGNED DEFAULT \"0\" NOT NULL;\n";
cerr << "ALTER TABLE `zone` CHANGE `minium_status` `min_status` TINYINT(3) UNSIGNED DEFAULT \"0\" NOT NULL;\n";
cerr << "ALTER TABLE `zone` ADD flag_needed VARCHAR(128) NOT NULL DEFAULT '';\n";
safe_delete_array(query);
}
return false;
}
bool Database::GetZoneLongName(const char* short_name, char** long_name, char* file_name, float* safe_x, float* safe_y, float* safe_z, int32* graveyard_id, int32* maxclients) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s'", short_name), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
if (long_name != 0) {
*long_name = strcpy(new char[strlen(row[0])+1], row[0]);
}
if (file_name != 0) {
if (row[1] == 0)
strcpy(file_name, short_name);
else
strcpy(file_name, row[1]);
}
if (safe_x != 0)
*safe_x = atof(row[2]);
if (safe_y != 0)
*safe_y = atof(row[3]);
if (safe_z != 0)
*safe_z = atof(row[4]);
if (graveyard_id != 0)
*graveyard_id = atoi(row[5]);
if (maxclients)
*maxclients = atoi(row[6]);
mysql_free_result(result);
return true;
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetZoneLongName query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return false;
}
int32 Database::GetZoneGraveyardID(int32 zone_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 GraveyardID = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT graveyard_id FROM zone WHERE zoneidnumber='%u'", zone_id), errbuf, &result))
{
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
GraveyardID = atoi(row[0]);
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetZoneGraveyardID query '" << query << "' " << errbuf << endl;
}
safe_delete_array(query);
return GraveyardID;
}
bool Database::GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid, float* graveyard_x, float* graveyard_y, float* graveyard_z, float* graveyard_heading) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone_id, x, y, z, heading FROM graveyard WHERE id=%i", graveyard_id), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
if(graveyard_zoneid != 0)
*graveyard_zoneid = atoi(row[0]);
if(graveyard_x != 0)
*graveyard_x = atof(row[1]);
if(graveyard_y != 0)
*graveyard_y = atof(row[2]);
if(graveyard_z != 0)
*graveyard_z = atof(row[3]);
if(graveyard_heading != 0)
*graveyard_heading = atof(row[4]);
mysql_free_result(result);
return true;
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetZoneGraveyard query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return false;
}
bool Database::LoadZoneNames() {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
query = new char[256];
strcpy(query, "SELECT MAX(zoneidnumber) FROM zone");
if (RunQuery(query, strlen(query), errbuf, &result)) {
safe_delete_array(query);
row = mysql_fetch_row(result);
if (row && row[0])
{
max_zonename = atoi(row[0]);
zonename_array = new char*[max_zonename+1];
for(unsigned int i=0; i<max_zonename; i++) {
zonename_array[i] = 0;
}
mysql_free_result(result);
MakeAnyLenString(&query, "SELECT zoneidnumber, short_name FROM zone");
if (RunQuery(query, strlen(query), errbuf, &result)) {
safe_delete_array(query);
while((row = mysql_fetch_row(result))) {
zonename_array[atoi(row[0])] = new char[strlen(row[1]) + 1];
strcpy(zonename_array[atoi(row[0])], row[1]);
Sleep(0);
}
mysql_free_result(result);
}
else {
cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
}
else {
mysql_free_result(result);
}
}
else {
cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return true;
}
int32 Database::GetZoneID(const char* zonename) {
if (zonename_array == 0)
return 0;
if (zonename == 0)
return 0;
for (unsigned int i=0; i<=max_zonename; i++) {
if (zonename_array[i] != 0 && strcasecmp(zonename_array[i], zonename) == 0) {
return i;
}
}
return 0;
}
const char* Database::GetZoneName(int32 zoneID, bool ErrorUnknown) {
if (zonename_array == 0) {
if (ErrorUnknown)
return "UNKNOWN";
else
return 0;
}
if (zoneID <= max_zonename) {
if (zonename_array[zoneID])
return zonename_array[zoneID];
else {
if (ErrorUnknown)
return "UNKNOWN";
else
return 0;
}
}
else {
if (ErrorUnknown)
return "UNKNOWN";
else
return 0;
}
return 0;
}
int8 Database::GetPEQZone(int32 zoneID){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int peqzone=0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT peqzone from zone where zoneidnumber='%i'", zoneID), errbuf, &result))
{
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
peqzone = atoi(row[0]);
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetPEQZone query '" << query << "' " << errbuf << endl;
}
safe_delete_array(query);
return peqzone;
}
bool Database::CheckNameFilter(const char* name, bool surname)
{
std::string str_name = name;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(surname)
{
// the minimum 4 is enforced by the client too
if(!name || strlen(name) < 3)
{
return false;
}
}
else
{
// the minimum 4 is enforced by the client too
if(!name || strlen(name) < 4 || strlen(name) > 64)
{
return false;
}
}
for (int i = 0; i < str_name.size(); i++)
{
if(!isalpha(str_name[i]))
{
return false;
}
}
for(int x = 0; x < str_name.size(); ++x)
{
str_name[x] = tolower(str_name[x]);
}
char c = '\0';
int8 num_c = 0;
for(int x = 0; x < str_name.size(); ++x)
{
if(str_name[x] == c)
{
num_c++;
}
else
{
num_c = 1;
c = str_name[x];
}
if(num_c > 2)
{
return false;
}
}
if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM name_filter"), errbuf, &result)) {
safe_delete_array(query);
while(row = mysql_fetch_row(result))
{
std::string current_row = row[0];
for(int x = 0; x < current_row.size(); ++x)
{
current_row[x] = tolower(current_row[x]);
}
if(str_name.find(current_row) != std::string::npos)
{
return false;
}
}
mysql_free_result(result);
return true;
}
else
{
cerr << "Error in CheckNameFilter query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return true;
}
bool Database::AddToNameFilter(const char* name) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO name_filter (name) values ('%s')", name), errbuf, 0, &affected_rows)) {
cerr << "Error in AddToNameFilter query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
if (affected_rows == 0) {
return false;
}
return true;
}
int32 Database::GetAccountIDFromLSID(int32 iLSID, char* oAccountName, sint16* oStatus) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
#ifdef DUAL_SERVER
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id2=%i OR lsaccount_id=%i", iLSID, iLSID), errbuf, &result))
#else
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id=%i", iLSID), errbuf, &result))
#endif
{
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
int32 account_id = atoi(row[0]);
if (oAccountName)
strcpy(oAccountName, row[1]);
if (oStatus)
*oStatus = atoi(row[2]);
mysql_free_result(result);
return account_id;
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else {
cerr << "Error in GetAccountIDFromLSID query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return 0;
}
return 0;
}
void Database::GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, status FROM account WHERE id=%i", id), errbuf, &result))
{
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
if (oAccountName)
strcpy(oAccountName, row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
}
mysql_free_result(result);
}
else
cerr << "Error in GetAccountFromID query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
void Database::ClearMerchantTemp(){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "delete from merchantlist_temp"), errbuf)) {
cerr << "Error in ClearMerchantTemp query '" << query << "' " << errbuf << endl;
}
safe_delete_array(query);
}
bool Database::UpdateName(const char* oldname, const char* newname) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
cout << "Renaming " << oldname << " to " << newname << "..." << endl;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET name='%s' WHERE name='%s';", newname, oldname), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
return false;
}
safe_delete_array(query);
if (affected_rows == 0)
{
return false;
}
return true;
}
// If the name is used or an error occurs, it returns false, otherwise it returns true
bool Database::CheckUsedName(const char* name)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
//if (strlen(name) > 15)
// return false;
if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM character_ where name='%s'", name), errbuf, &result)) {
cerr << "Error in CheckUsedName query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
else { // It was a valid Query, so lets do our counts!
safe_delete_array(query);
int32 tmp = mysql_num_rows(result);
mysql_free_result(result);
if (tmp > 0) // There is a Name! No change (Return False)
return false;
else // Everything is okay, so we go and do this.
return true;
}
}
int8 Database::GetServerType()
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT value FROM variables WHERE varname='ServerType'"), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
int8 ServerType = atoi(row[0]);
mysql_free_result(result);
return ServerType;
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetServerType query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
return 0;
}
bool Database::MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if(zonename == NULL || strlen(zonename) == 0)
return(false);
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s',zoneid=%i,x=-1, y=-1, z=-1 WHERE name='%s'", zonename,zoneid, charname), errbuf, 0,&affected_rows)) {
cerr << "Error in MoveCharacterToZone(name) query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);
if (affected_rows == 0)
return false;
return true;
}
bool Database::MoveCharacterToZone(const char* charname, const char* zonename) {
return MoveCharacterToZone(charname, zonename, GetZoneID(zonename));
}
bool Database::MoveCharacterToZone(int32 iCharID, const char* iZonename) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s', zoneid=%i, x=-1, y=-1, z=-1 WHERE id=%i", iZonename, GetZoneID(iZonename), iCharID), errbuf, 0,&affected_rows)) {
cerr << "Error in MoveCharacterToZone(id) query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);
if (affected_rows == 0)
return false;
return true;
}
int8 Database::CopyCharacter(const char* oldname, const char* newname, int32 acctid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
PlayerProfile_Struct* pp;
ExtendedProfile_Struct* ext;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile, guild, guildrank, extprofile FROM character_ WHERE name='%s'", oldname), errbuf, &result)) {
safe_delete_array(query);
row = mysql_fetch_row(result);
pp = (PlayerProfile_Struct*)row[0];
strcpy(pp->name, newname);
ext = (ExtendedProfile_Struct*)row[3];
mysql_free_result(result);
}
else {
cerr << "Error in CopyCharacter read query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return 0;
}
int32 affected_rows = 0;
char query2[276 + sizeof(PlayerProfile_Struct)*2 + sizeof(ExtendedProfile_Struct)*2 + 1];
char* end=query2;
end += sprintf(end, "INSERT INTO character_ SET zonename=\'%s\', x = %f, y = %f, z = %f, profile=\'", GetZoneName(pp->zone_id), pp->x, pp->y, pp->z);
end += DoEscapeString(end, (char*) pp, sizeof(PlayerProfile_Struct));
end += sprintf(end,"\', extprofile=\'");
end += DoEscapeString(end, (char*) ext, sizeof(ExtendedProfile_Struct));
end += sprintf(end, "\', account_id=%d, name='%s'", acctid, newname);
if (!RunQuery(query2, (int32) (end - query2), errbuf, 0, &affected_rows)) {
cerr << "Error in CopyCharacter query '" << query << "' " << errbuf << endl;
return 0;
}
// @merth: Need to copy inventory as well (and shared bank?)
if (affected_rows == 0) {
return 0;
}
return 1;
}
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked) values('%s','%s','%s')", accountname, charactername, hacked), errbuf, 0,&affected_rows)) {
cerr << "Error in SetHackerFlag query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);
if (affected_rows == 0)
{
return false;
}
return true;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka: Utilize the "hacker" table, but also give zone information.
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {
cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;
return false;
}
safe_delete_array(query);
if (affected_rows == 0)
{
return false;
}
return true;
}
int8 Database::GetRaceSkill(int8 skillid, int8 in_race)
{
int16 race_cap = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
MYSQL_RES *result;
MYSQL_ROW row;
//Check for a racial cap!
if (RunQuery(query, MakeAnyLenString(&query, "SELECT skillcap from race_skillcaps where skill = %i && race = %i", skillid, in_race), errbuf, &result, &affected_rows))
{
if (affected_rows != 0)
{
row = mysql_fetch_row(result);
race_cap = atoi(row[0]);
}
delete[] query;
mysql_free_result(result);
}
return race_cap;
}
int8 Database::GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level)
{
int8 skill_level = 0, skill_formula = 0;
int16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
MYSQL_RES *result;
MYSQL_ROW row;
//Fetch the data from DB.
if (RunQuery(query, MakeAnyLenString(&query, "SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class), errbuf, &result, &affected_rows))
{
if (affected_rows != 0)
{
row = mysql_fetch_row(result);
skill_level = atoi(row[0]);
skill_formula = atoi(row[1]);
skill_cap = atoi(row[2]);
if (atoi(row[3]) > skill_cap)
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = atoi(row[4]);
}
delete[] query;
mysql_free_result(result);
}
int race_skill = GetRaceSkill(skillid,in_race);
if (race_skill > 0 && (race_skill > skill_cap || skill_cap == 0 || in_level < skill_level))
return race_skill;
if (skill_cap == 0) //Can't train this skill at all.
return 255; //Untrainable
if (in_level < skill_level)
return 254; //Untrained
//Determine pre-51 level-based cap
if (skill_formula > 0)
base_cap = in_level*skill_formula+skill_formula;
if (base_cap > skill_cap || skill_formula == 0)
base_cap = skill_cap;
//If post 50, add post 50 cap to base cap.
if (in_level > 50 && skill_cap2 > 0)
base_cap += skill_cap2*(in_level-50);
//No cap should ever go above its post50cap
if (skill_cap3 > 0 && base_cap > skill_cap3)
base_cap = skill_cap3;
//Base cap is now the max value at the person's level, return it!
return base_cap;
}
int32 Database::GetCharacterInfo(const char* iName, int32* oAccID, int32* oZoneID, int32* oInstanceID, float* oX, float* oY, float* oZ) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, account_id, zonename, instanceid, x, y, z FROM character_ WHERE name='%s'", iName), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
int32 charid = atoi(row[0]);
if (oAccID)
*oAccID = atoi(row[1]);
if (oZoneID)
*oZoneID = GetZoneID(row[2]);
if(oInstanceID)
*oInstanceID = atoi(row[3]);
if (oX)
*oX = atof(row[4]);
if (oY)
*oY = atof(row[5]);
if (oZ)
*oZ = atof(row[6]);
mysql_free_result(result);
return charid;
}
mysql_free_result(result);
}
else {
cerr << "Error in GetCharacterInfo query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return 0;
}
bool Database::UpdateLiveChar(char* charname,int32 lsaccount_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET charname='%s' WHERE id=%i;",charname, lsaccount_id), errbuf)) {
cerr << "Error in UpdateLiveChar query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return false;
}
safe_delete_array(query);
return true;
}
bool Database::GetLiveChar(int32 account_id, char* cname) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charname FROM account WHERE id=%i", account_id), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
strcpy(cname,row[0]);
mysql_free_result(result);
return true;
}
mysql_free_result(result);
}
else {
cerr << "Error in GetLiveChar query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
}
return false;
}
void Database::SetLFP(int32 CharID, bool LFP) {
char ErrBuf[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfp=%i where id=%i",LFP, CharID), ErrBuf))
LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);
safe_delete_array(Query);
}
void Database::SetLFG(int32 CharID, bool LFG) {
char ErrBuf[MYSQL_ERRMSG_SIZE];
char *Query = 0;
if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfg=%i where id=%i",LFG, CharID), ErrBuf))
LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);
safe_delete_array(Query);
}
void Database::AddReport(std::string who, std::string against, std::string lines)
{
char ErrBuf[MYSQL_ERRMSG_SIZE];
char *Query = 0;
char *escape_str = new char[lines.size()*2+1];
DoEscapeString(escape_str, lines.c_str(), lines.size());
if (!RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str), ErrBuf))
LogFile->write(EQEMuLog::Error, "Error adding a report for %s: %s", who.c_str(), ErrBuf);
safe_delete_array(Query);
safe_delete_array(escape_str);
}
void Database::SetGroupID(const char* name,int32 id, int32 charid){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(id == 0){ //removing you from table
if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where charid=%i and name='%s'",charid, name), errbuf))
printf("Unable to get group id: %s\n",errbuf);
}
else{
if (!RunQuery(query, MakeAnyLenString(&query, "replace into group_id set charid=%i, groupid=%i, name='%s'",charid, id, name), errbuf))
printf("Unable to get group id: %s\n",errbuf);
}
#ifdef _EQDEBUG
printf("Set group id on '%s' to %d\n", name, id);
#endif
safe_delete_array(query);
}
void Database::ClearGroup(int32 gid) {
ClearGroupLeader(gid);
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(gid == 0) { //clear all groups
//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid!=0"), errbuf))
if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id"), errbuf))
printf("Unable to clear groups: %s\n",errbuf);
} else { //clear a specific group
//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid = %lu", gid), errbuf))
if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where groupid = %lu", (unsigned long)gid), errbuf))
printf("Unable to clear groups: %s\n",errbuf);
}
safe_delete_array(query);
}
int32 Database::GetGroupID(const char* name){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 groupid=0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT groupid from group_id where name='%s'", name), errbuf, &result)) {
if((row = mysql_fetch_row(result)))
{
if(row[0])
groupid=atoi(row[0]);
}
else
printf("Unable to get group id, char not found!\n");
mysql_free_result(result);
}
else
printf("Unable to get group id: %s\n",errbuf);
safe_delete_array(query);
return groupid;
}
char* Database::GetGroupLeaderForLogin(const char* name,char* leaderbuf){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
PlayerProfile_Struct pp;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile from character_ where name='%s'", name), errbuf, &result)) {
row = mysql_fetch_row(result);
unsigned long* lengths = mysql_fetch_lengths(result);
if (lengths[0] == sizeof(PlayerProfile_Struct)) {
memcpy(&pp, row[0], sizeof(PlayerProfile_Struct));
strcpy(leaderbuf,pp.groupMembers[0]);
}
mysql_free_result(result);
}
else{
printf("Unable to get leader name: %s\n",errbuf);
}
safe_delete_array(query);
return leaderbuf;
}
void Database::SetGroupLeaderName(int32 gid, const char* name){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "Replace into group_leaders set gid=%lu, leadername='%s'",(unsigned long)gid,name), errbuf))
printf("Unable to set group leader: %s\n",errbuf);
safe_delete_array(query);
}
char *Database::GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist, char *marknpc, GroupLeadershipAA_Struct* GLAA){
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES* result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT leadername, assist, marknpc, leadershipaa FROM group_leaders WHERE gid=%lu",(unsigned long)gid),
errbuf, &result)) {
safe_delete_array(query);
row = mysql_fetch_row(result);
unsigned long* Lengths = mysql_fetch_lengths(result);
if(row != NULL){
if(leaderbuf)
strcpy(leaderbuf, row[0]);
if(assist)
strcpy(assist, row[1]);
if(marknpc)
strcpy(marknpc, row[2]);
if(GLAA && (Lengths[3] == sizeof(GroupLeadershipAA_Struct)))
memcpy(GLAA, row[3], sizeof(GroupLeadershipAA_Struct));
mysql_free_result(result);
return leaderbuf;
}
}
else
safe_delete_array(query);
if(leaderbuf)
strcpy(leaderbuf, "UNKNOWN");
if(assist)
assist[0] = 0;
if(marknpc)
marknpc[0] = 0;
return leaderbuf;
}
void Database::ClearGroupLeader(int32 gid){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(gid == 0) { //clear all group leaders
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders"), errbuf))
printf("Unable to clear group leaders: %s\n",errbuf);
} else { //clear a specific group leader
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders where gid = %lu", (unsigned long)gid), errbuf))
printf("Unable to clear group leader: %s\n",errbuf);
}
safe_delete_array(query);
}
bool FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap)
{
MYSQL_FIELD *fields;
MYSQL_ROW row;
unsigned long num_fields,i;
bool retval=false;
rowmap.clear();
if (result && (num_fields=mysql_num_fields(result)) && (row = mysql_fetch_row(result))!=NULL && (fields = mysql_fetch_fields(result))!=NULL) {
retval=true;
for(i=0;i<num_fields;i++) {
rowmap[fields[i].name]=(row[i] ? row[i] : "");
}
}
return retval;
}
int8 Database::GetAgreementFlag(int32 acctid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES* result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT rulesflag FROM account WHERE id=%i",acctid), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
row = mysql_fetch_row(result);
int8 flag = atoi(row[0]);
mysql_free_result(result);
return flag;
}
}
else
{
safe_delete_array(query);
}
return 0;
}
void Database::SetAgreementFlag(int32 acctid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET rulesflag=1 where id=%i",acctid), errbuf, 0, &affected_rows)) {
safe_delete_array(query);
}
else
safe_delete_array(query);
}
void Database::ClearRaid(int32 rid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(rid == 0) { //clear all raids
if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members"), errbuf))
printf("Unable to clear raids: %s\n",errbuf);
} else { //clear a specific group
if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members where raidid = %lu", (unsigned long)rid), errbuf))
printf("Unable to clear raids: %s\n",errbuf);
}
safe_delete_array(query);
}
void Database::ClearRaidDetails(int32 rid) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(rid == 0) { //clear all raids
if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details"), errbuf))
printf("Unable to clear raid details: %s\n",errbuf);
} else { //clear a specific group
if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details where raidid = %lu", (unsigned long)rid), errbuf))
printf("Unable to clear raid details: %s\n",errbuf);
}
safe_delete_array(query);
}
int32 Database::GetRaidID(const char* name){
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 raidid=0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT raidid from raid_members where name='%s'", name),
errbuf, &result)) {
if((row = mysql_fetch_row(result)))
{
if(row[0])
raidid=atoi(row[0]);
}
else
printf("Unable to get raid id, char not found!\n");
mysql_free_result(result);
}
else
printf("Unable to get raid id: %s\n",errbuf);
safe_delete_array(query);
return raidid;
}
const char *Database::GetRaidLeaderName(int32 rid)
{
static char name[128];
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM raid_members WHERE raidid=%u AND israidleader=1",
rid), errbuf, &result)) {
if((row = mysql_fetch_row(result)) != NULL)
{
memset(name, 0, 128);
strcpy(name, row[0]);
mysql_free_result(result);
safe_delete_array(query);
return name;
}
else
printf("Unable to get raid id, char not found!\n");
mysql_free_result(result);
}
else
printf("Unable to get raid id: %s\n",errbuf);
safe_delete_array(query);
return "UNKNOWN";
}
bool Database::VerifyInstanceAlive(int16 instance_id, int32 char_id)
{
//we are not saved to this instance so set our instance to 0
if(!CharacterInInstanceGroup(instance_id, char_id))
{
SetCharacterInstance(0, char_id);
return false;
}
if(CheckInstanceExpired(instance_id))
{
DeleteInstance(instance_id);
SetCharacterInstance(0, char_id);
return false;
}
return true;
}
bool Database::VerifyZoneInstance(int32 zone_id, int16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id=%u AND zone=%u",
instance_id, zone_id), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
mysql_free_result(result);
return true;
}
else
{
mysql_free_result(result);
return false;
}
}
else
{
safe_delete_array(query);
return false;
}
return false;
}
bool Database::CharacterInInstanceGroup(int16 instance_id, int32 char_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
bool lockout_instance_player = false;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player where id=%u AND charid=%u",
instance_id, char_id), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) == 1)
{
lockout_instance_player = true;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
return lockout_instance_player;
}
void Database::SetCharacterInstance(int16 instance_id, int32 char_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET instanceid=%u WHERE id=%u", instance_id,
char_id), errbuf, &result))
{
safe_delete_array(query);
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::DeleteInstance(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout WHERE id=%u", instance_id), errbuf))
{
safe_delete_array(query);
}
else
{
safe_delete_array(query);
}
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%u", instance_id), errbuf))
{
safe_delete_array(query);
}
else
{
safe_delete_array(query);
}
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE instance_id=%u", instance_id), errbuf))
{
safe_delete_array(query);
}
else
{
safe_delete_array(query);
}
BuryCorpsesInInstance(instance_id);
}
bool Database::CheckInstanceExpired(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 start_time = 0;
int32 duration = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u",
instance_id), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
start_time = atoi(row[0]);
duration = atoi(row[1]);
}
else
{
mysql_free_result(result);
return true;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
return true;
}
timeval tv;
gettimeofday(&tv, NULL);
if((start_time + duration) <= tv.tv_sec)
{
return true;
}
return false;
}
int32 Database::ZoneIDFromInstanceID(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_lockout where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
ret = atoi(row[0]);
mysql_free_result(result);
return ret;
}
else
{
mysql_free_result(result);
return 0;
}
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
int32 Database::VersionFromInstanceID(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
ret = atoi(row[0]);
mysql_free_result(result);
return ret;
}
else
{
mysql_free_result(result);
return 0;
}
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
int32 Database::GetTimeRemainingInstance(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 start_time = 0;
int32 duration = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u",
instance_id), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
start_time = atoi(row[0]);
duration = atoi(row[1]);
}
else
{
mysql_free_result(result);
return 0;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
return 0;
}
timeval tv;
gettimeofday(&tv, NULL);
return ((start_time + duration) - tv.tv_sec);
}
bool Database::GetUnusedInstanceID(uint16 &instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT COUNT(*) FROM instance_lockout"), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
int count = atoi(row[0]);
if(count == 0)
{
mysql_free_result(result);
instance_id = 1;
return true;
}
}
else
{
mysql_free_result(result);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
instance_id = 0;
return false;
}
int32 count = 1;
int32 max = 65535;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout ORDER BY id"), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
while(row = mysql_fetch_row(result))
{
if(count < atoi(row[0]))
{
instance_id = count;
mysql_free_result(result);
return true;
}
else if(count > max)
{
instance_id = 0;
mysql_free_result(result);
return false;
}
else
{
count++;
}
}
}
else
{
mysql_free_result(result);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
instance_id = count;
return true;
}
//perhaps purge any expireds too
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout (id, zone, version, start_time, duration)"
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration), errbuf))
{
safe_delete_array(query);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
void Database::PurgeExpiredInstances()
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int16 id = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where "
"(start_time+duration)<=UNIX_TIMESTAMP()"), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) > 0)
{
row = mysql_fetch_row(result);
while(row != NULL)
{
id = atoi(row[0]);
DeleteInstance(id);
row = mysql_fetch_row(result);
}
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout_player(id, charid) "
"values(%lu, %lu)", (unsigned long)instance_id, (unsigned long)char_id), errbuf))
{
safe_delete_array(query);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu AND charid=%lu",
(unsigned long)instance_id, (unsigned long)char_id), errbuf))
{
safe_delete_array(query);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
bool Database::RemoveClientsFromInstance(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu",
(unsigned long)instance_id), errbuf))
{
safe_delete_array(query);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
bool Database::CheckInstanceExists(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_lockout where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
mysql_free_result(result);
return true;
}
mysql_free_result(result);
return false;
}
else
{
safe_delete_array(query);
return false;
}
return false;
}
void Database::BuryCorpsesInInstance(uint16 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET IsBurried=1, instanceid=0 WHERE instanceid=%u",
instance_id), errbuf, &result))
{
mysql_free_result(result);
}
safe_delete_array(query);
}
int16 Database::GetInstanceVersion(uint16 instance_id)
{
if(instance_id < 1)
return 0;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
ret = atoi(row[0]);
mysql_free_result(result);
return ret;
}
else
{
mysql_free_result(result);
return 0;
}
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
int16 Database::GetInstanceID(const char* zone, int32 charid, int16 version)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int16 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
"instance_lockout_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
ret = atoi(row[0]);
mysql_free_result(result);
return ret;
}
else
{
mysql_free_result(result);
return 0;
}
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
int16 Database::GetInstanceID(int32 zone, int32 charid, int16 version)
{
if(!zone)
return 0;
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int16 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
"instance_lockout_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
ret = atoi(row[0]);
mysql_free_result(result);
return ret;
}
else
{
mysql_free_result(result);
return 0;
}
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
void Database::AssignGroupToInstance(int32 gid, int32 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 zone_id = ZoneIDFromInstanceID(instance_id);
int16 version = VersionFromInstanceID(instance_id);
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id WHERE groupid=%u", gid),
errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 charid = atoi(row[0]);
if(GetInstanceID(zone_id, charid, version) == 0)
{
AddClientToInstance(instance_id, charid);
}
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::AssignRaidToInstance(int32 rid, int32 instance_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 zone_id = ZoneIDFromInstanceID(instance_id);
int16 version = VersionFromInstanceID(instance_id);
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members WHERE raidid=%u", rid),
errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 charid = atoi(row[0]);
if(GetInstanceID(zone_id, charid, version) == 0)
{
AddClientToInstance(instance_id, charid);
}
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid)
{
int16 id = GetInstanceID(zone, charid, version);
if(id != 0)
return;
char ln[128];
memset(ln, 0, 128);
strcpy(ln, GetGroupLeadershipInfo(gid, ln));
int32 l_charid = GetCharacterID((const char*)ln);
int16 l_id = GetInstanceID(zone, l_charid, version);
if(l_id == 0)
return;
AddClientToInstance(l_id, charid);
}
void Database::FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid)
{
int16 id = GetInstanceID(zone, charid, version);
if(id != 0)
return;
int32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
int16 l_id = GetInstanceID(zone, l_charid, version);
if(l_id == 0)
return;
AddClientToInstance(l_id, charid);
}
void Database::SetInstanceDuration(int16 instance_id, int32 new_duration)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_lockout` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int16 m_avg_level = 0;
int8 num_in_group = 0;
int16 min_level = 2000;
int16 max_level = 0;
#ifndef GROUP_ADV_USE_VIEW
if (RunQuery(query, MakeAnyLenString(&query, "SELECT character_.level FROM character_, group_id"
" WHERE character_.id=group_id.charid AND group_id.groupid=%u", gid), errbuf, &result))
#else
if (RunQuery(query, MakeAnyLenString(&query, "select level from vwGroups where groupid = %u", gid), errbuf, &result))
#endif
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int16 m_lvl = atoi(row[0]);
m_avg_level += m_lvl;
if(m_lvl < min_level)
min_level = m_lvl;
if(m_lvl > max_level)
max_level = m_lvl;
num_in_group++;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
avg_level = (m_avg_level / num_in_group);
range = max_level-min_level;
}
void Database::RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int16 m_avg_level = 0;
int8 num_in_group = 0;
int16 min_level = 2000;
int16 max_level = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT raid_members.level FROM raid_members "
"WHERE raid_members.raidid=%u", rid), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int16 m_lvl = atoi(row[0]);
m_avg_level += m_lvl;
if(m_lvl < min_level)
min_level = m_lvl;
if(m_lvl > max_level)
max_level = m_lvl;
num_in_group++;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
avg_level = (m_avg_level / num_in_group);
range = max_level-min_level;
}
int32 Database::CreateAdventure(int32 adventure_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
int32 last_insert_id = 0;
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_details` SET adventure_id=%u,"
" time_created=UNIX_TIMESTAMP()", adventure_id), errbuf, 0, &affected_rows, &last_insert_id)) {
safe_delete_array(query);
return 0;
}
safe_delete_array(query);
if (affected_rows == 0)
{
return 0;
}
if (last_insert_id == 0)
{
return 0;
}
return last_insert_id;
}
void Database::AddPlayerToAdventure(int32 id, int32 charid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_members` SET"
" id=%u, charid=%u", id, charid), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::RemovePlayerFromAdventure(int32 id, int32 charid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
" id=%u AND charid=%u", id, charid), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::RemovePlayersFromAdventure(int32 id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
" id=%u", id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::AddGroupToAdventure(int32 id, int32 gid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id "
"WHERE groupid=%u", gid), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 charid = atoi(row[0]);
AddPlayerToAdventure(id, charid);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::AddRaidToAdventure(int32 id, int32 rid)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members "
"WHERE raidid=%u", rid), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 charid = atoi(row[0]);
AddPlayerToAdventure(id, charid);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::DestroyAdventure(int32 id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details` WHERE id=%u", id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE id=%u", id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
bool Database::GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count,
int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 adv_id = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1",
charid), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
adv_id = atoi(row[0]);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
if(adv_id == 0)
return false;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `adventure_id`, `instance_id`, `count`, `assassinate_count`, `status`, "
"`time_created`, `time_zoned`, `time_completed` FROM `adventure_details` WHERE id=%u LIMIT 1", adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
adventure_id = atoi(row[0]);
instance_id = atoi(row[1]);
count = atoi(row[2]);
ass_count = atoi(row[3]);
status = atoi(row[4]);
time_c = atoi(row[5]);
time_z = atoi(row[6]);
time_comp = atoi(row[7]);
id = adv_id;
}
mysql_free_result(result);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
int32 Database::GetAdventureID(int32 char_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 adv_id = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1",
char_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
adv_id = atoi(row[0]);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
return adv_id;
}
int32 Database::CountPlayersInAdventure(int32 id)
{
//SELECT `charid` FROM `adventure_members` WHERE id=%u
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int count = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE "
"id=%u", id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
count++;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
return count;
}
void Database::PurgeAdventures()
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details`"), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members`"), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::AddAdventureToInstance(int32 adv_id, int32 inst_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u",
adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 id = atoi(row[0]);
AddClientToInstance(inst_id, id);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
void Database::UpdateAdventureStatus(int32 adv_id, int32 status)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET status=%u WHERE id=%u",
status, adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET instance_id=%d, "
"time_zoned=%u WHERE id=%u", inst_id, time, adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::UpdateAdventureCompleted(int32 adv_id, int32 time)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET time_completed=%u "
"WHERE id=%u", time, adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::UpdateAdventureCount(int32 adv_id, int32 new_count)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=%u "
"WHERE id=%u", new_count, adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
void Database::IncrementAdventureCount(int32 adv_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=count+1 "
"WHERE id=%u", adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
int32 Database::GetAdventureCount(int32 adv_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `count` FROM `adventure_details` WHERE id=%u",
adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 count = atoi(row[0]);
return count;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
return 0;
}
return 0;
}
bool Database::AdventureExists(int32 adv_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_details` WHERE id=%u",
adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
return true;
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
return false;
}
return false;
}
void Database::UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected = 0;
std::string field;
if(win)
{
switch(theme)
{
case 1:
{
field = "guk_wins";
break;
}
case 2:
{
field = "mir_wins";
break;
}
case 3:
{
field = "mmc_wins";
break;
}
case 4:
{
field = "ruj_wins";
break;
}
case 5:
{
field = "tak_wins";
break;
}
default:
{
return;
}
}
}
else
{
switch(theme)
{
case 1:
{
field = "guk_losses";
break;
}
case 2:
{
field = "mir_losses";
break;
}
case 3:
{
field = "mmc_losses";
break;
}
case 4:
{
field = "ruj_losses";
break;
}
case 5:
{
field = "tak_losses";
break;
}
default:
{
return;
}
}
}
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_stats` SET %s=%s+1 WHERE player_id=%u",
field.c_str(), field.c_str(), char_id), errbuf, NULL, &affected))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
if(affected == 0)
{
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_stats` SET %s=1, player_id=%u",
field.c_str(), char_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
}
void Database::UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(!AdventureExists(adv_id))
return;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u",
adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
int32 charid = atoi(row[0]);
UpdateAdventureStatsEntry(charid, theme, win);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
}
}
bool Database::GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w,
int32 &tak_w, int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `guk_wins`, `mir_wins`, `mmc_wins`, `ruj_wins`, `tak_wins`, "
"`guk_losses`, `mir_losses`, `mmc_losses`, `ruj_losses`, `tak_losses` FROM `adventure_stats` WHERE player_id=%u",
char_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
guk_w = atoi(row[0]);
mir_w = atoi(row[1]);
mmc_w = atoi(row[2]);
ruj_w = atoi(row[3]);
tak_w = atoi(row[4]);
guk_l = atoi(row[5]);
mir_l = atoi(row[6]);
mmc_l = atoi(row[7]);
ruj_l = atoi(row[8]);
tak_l = atoi(row[9]);
}
mysql_free_result(result);
return true;
}
else
{
safe_delete_array(query);
return false;
}
}
int32 Database::AdventureGetAssassinateKills(int32 adv_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
int32 ret_val = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT `assassinate_count` FROM"
" `adventure_details` WHERE id=%u", adv_id), errbuf, &result))
{
safe_delete_array(query);
while((row = mysql_fetch_row(result)) != NULL)
{
ret_val = atoi(row[0]);
}
mysql_free_result(result);
return ret_val;
}
else
{
safe_delete_array(query);
return ret_val;
}
}
void Database::AdventureSetAssassinateKills(int32 adv_id, int32 kills)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET assassinate_count=%u "
"WHERE id=%u", kills, adv_id), errbuf))
{
safe_delete_array(query);
}
else
{
//error
safe_delete_array(query);
}
}
database.h
Code:
#ifndef EQEMU_DATABASE_H
#define EQEMU_DATABASE_H
#define AUTHENTICATION_TIMEOUT 60
#define INVALID_ID 0xFFFFFFFF
#include "debug.h"
#include "types.h"
#include "dbcore.h"
#include "linked_list.h"
#include "eq_packet_structs.h"
/*#include "EQStream.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "Mutex.h"
#include "Item.h"
#include "extprofile.h"*/
#include <string>
#include <vector>
#include <map>
using namespace std;
//atoi is not int32 or uint32 safe!!!!
#define atoul(str) strtoul(str, NULL, 10)
//class Spawn;
class Corpse;
class Spawn2;
class NPC;
class SpawnGroupList;
class Petition;
class Client;
struct Combine_Struct;
//struct Faction;
//struct FactionMods;
//struct FactionValue;
struct ZonePoint;
struct NPCType;
class Inventory;
class ItemInst;
struct EventLogDetails_Struct {
int32 id;
char accountname[64];
int32 account_id;
sint16 status;
char charactername[64];
char targetname[64];
char timestamp[64];
char descriptiontype[64];
char details[128];
};
struct CharacterEventLog_Struct {
int32 count;
int8 eventid;
EventLogDetails_Struct eld[255];
};
// Added By Hogie
// INSERT into variables (varname,value) values('decaytime [minlevel] [maxlevel]','[number of seconds]');
// IE: decaytime 1 54 = Levels 1 through 54
// decaytime 55 100 = Levels 55 through 100
// It will always put the LAST time for the level (I think) from the Database
struct npcDecayTimes_Struct {
int16 minlvl;
int16 maxlvl;
int32 seconds;
};
// Added By Hogie -- End
struct VarCache_Struct {
char varname[26]; // varname is char(25) in database
char value[0];
};
struct PlayerProfile_Struct;
struct GuildRankLevel_Struct;
struct GuildRanks_Struct;
struct ExtendedProfile_Struct;
struct GuildMember_Struct;
class PTimerList;
class Database : public DBcore {
public:
Database();
Database(const char* host, const char* user, const char* passwd, const char* database,int32 port);
bool Connect(const char* host, const char* user, const char* passwd, const char* database,int32 port);
~Database();
// void ExtraOptions();
/*
* General Character Related Stuff
*/
bool MoveCharacterToZone(const char* charname, const char* zonename);
bool MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid);
bool MoveCharacterToZone(int32 iCharID, const char* iZonename);
bool UpdateName(const char* oldname, const char* newname);
bool SetHackerFlag(const char* accountname, const char* charactername, const char* hacked);
bool SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
bool AddToNameFilter(const char* name);
bool ReserveName(int32 account_id, char* name);
bool CreateCharacter(uint32 account_id, char* name, int16 gender, int16 race, int16 class_, int8 str, int8 sta, int8 cha, int8 dex, int8 int_, int8 agi, int8 wis, int8 face);
bool StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext);
bool DeleteCharacter(char* name);
int8 CopyCharacter(const char* oldname, const char* newname, int32 acctid);
/*
* General Information Getting Queries
*/
bool CheckNameFilter(const char* name, bool surname = false);
bool CheckUsedName(const char* name);
int32 GetAccountIDByChar(const char* charname, int32* oCharID = 0);
uint32 GetAccountIDByChar(uint32 char_id);
int32 GetAccountIDByName(const char* accname, sint16* status = 0, int32* lsid = 0);
void GetAccountName(int32 accountid, char* name, int32* oLSAccountID = 0);
void GetCharName(int32 char_id, char* name);
int32 GetCharacterInfo(const char* iName, int32* oAccID = 0, int32* oZoneID = 0, int32* oInstanceID = 0,float* oX = 0, float* oY = 0, float* oZ = 0);
int32 GetCharacterID(const char *name);
bool CheckBannedIPs(const char* loginIP); //Lieka Edit: Check incomming connection against banned IP table.
bool AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit: Add IP address to the Banned_IPs table.
bool CheckGMIPs(const char* loginIP, int32 account_id);
bool AddGMIP(char* ip_address, char* name);
void LoginIP(int32 AccountID, const char* LoginIP);
/*
* Instancing Stuff
*/
bool VerifyZoneInstance(int32 zone_id, int16 instance_id);
bool VerifyInstanceAlive(int16 instance_id, int32 char_id);
bool CharacterInInstanceGroup(int16 instance_id, int32 char_id);
void SetCharacterInstance(int16 instance_id, int32 char_id);
void DeleteInstance(uint16 instance_id);
bool CheckInstanceExpired(uint16 instance_id);
int32 ZoneIDFromInstanceID(uint16 instance_id);
int32 VersionFromInstanceID(uint16 instance_id);
int32 GetTimeRemainingInstance(uint16 instance_id);
bool GetUnusedInstanceID(uint16 &instance_id);
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
void PurgeExpiredInstances();
bool AddClientToInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientsFromInstance(uint16 instance_id);
bool CheckInstanceExists(uint16 instance_id);
void BuryCorpsesInInstance(uint16 instance_id);
int16 GetInstanceVersion(uint16 instance_id);
int16 GetInstanceID(const char* zone, int32 charid, int16 version);
int16 GetInstanceID(int32 zone, int32 charid, int16 version);
void AssignGroupToInstance(int32 gid, int32 instance_id);
void AssignRaidToInstance(int32 rid, int32 instance_id);
void FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid);
void FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid);
void SetInstanceDuration(int16 instance_id, int32 new_duration);
/*
* Adventure
*/
void GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range);
void RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range);
int32 CreateAdventure(int32 adventure_id);
void AddPlayerToAdventure(int32 id, int32 charid);
void RemovePlayerFromAdventure(int32 id, int32 charid);
void RemovePlayersFromAdventure(int32 id);
void AddGroupToAdventure(int32 id, int32 gid);
void AddRaidToAdventure(int32 id, int32 rid);
void DestroyAdventure(int32 id);
bool GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count,
int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp);
int32 GetAdventureID(int32 char_id);
int32 CountPlayersInAdventure(int32 id);
void PurgeAdventures();
void AddAdventureToInstance(int32 adv_id, int32 inst_id);
void UpdateAdventureStatus(int32 adv_id, int32 status);
void UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time);
void UpdateAdventureCompleted(int32 adv_id, int32 time);
void UpdateAdventureCount(int32 adv_id, int32 new_count);
void IncrementAdventureCount(int32 adv_id);
int32 GetAdventureCount(int32 adv_id);
bool AdventureExists(int32 adv_id);
void UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win);
void UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win);
bool GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w, int32 &tak_w,
int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l);
int32 AdventureGetAssassinateKills(int32 adv_id);
void AdventureSetAssassinateKills(int32 adv_id, int32 kills);
/*
* Account Related
*/
int32 GetMiniLoginAccount(char* ip);
void GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus);
int32 CheckLogin(const char* name, const char* password, sint16* oStatus = 0);
sint16 CheckStatus(int32 account_id);
#ifdef DUAL_SERVER
int32 CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0, int32 lsaccount_id2 = 0);
int32 pLSID;
inline int32 LSID() const { return pLSID; }
#else
int32 CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0);
#endif
bool DeleteAccount(const char* name);
bool SetAccountStatus(const char* name, sint16 status);
bool SetLocalPassword(uint32 accid, const char* password);
int32 GetAccountIDFromLSID(int32 iLSID, char* oAccountName = 0, sint16* oStatus = 0);
bool UpdateLiveChar(char* charname,int32 lsaccount_id);
bool GetLiveChar(int32 account_id, char* cname);
int8 GetAgreementFlag(int32 acctid);
void SetAgreementFlag(int32 acctid);
/*
* Groups
*/
int32 GetGroupID(const char* name);
void SetGroupID(const char* name, int32 id, int32 charid);
void ClearGroup(int32 gid = 0);
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
void SetGroupLeaderName(int32 gid, const char* name);
char* GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist = NULL, char *marknpc = NULL,
GroupLeadershipAA_Struct* GLAA = NULL);
void ClearGroupLeader(int32 gid = 0);
/*
* Raids
*/
void ClearRaid(int32 rid = 0);
void ClearRaidDetails(int32 rid = 0);
int32 GetRaidID(const char* name);
const char *GetRaidLeaderName(int32 rid);
/*
* Database Varaibles
*/
bool GetVariable(const char* varname, char* varvalue, int16 varvalue_len);
bool SetVariable(const char* varname, const char* varvalue);
bool LoadVariables();
int32 LoadVariables_MQ(char** query);
bool LoadVariables_result(MYSQL_RES* result);
/*
* General Queries
*/
bool LoadZoneNames();
bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int32* graveyard_id = 0, int32* maxclients = 0);
bool GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
int32 GetZoneGraveyardID(int32 zone_id);
int32 GetZoneID(const char* zonename);
int8 GetPEQZone(int32 zoneID);
const char* GetZoneName(int32 zoneID, bool ErrorUnknown = false);
int8 GetServerType();
bool GetSafePoints(const char* short_name, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0); //Angelox4
bool GetSafePoints(int32 zoneID, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0) { return GetSafePoints(GetZoneName(zoneID), safe_x, safe_y, safe_z, minstatus, minlevel, flag_needed, canzone); } //Angelox4
int8 GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level);
int8 GetRaceSkill(int8 skillid, int8 in_race);
bool LoadPTimers(uint32 charid, PTimerList &into);
void ClearPTimers(uint32 charid);
void ClearMerchantTemp();
void SetLFP(int32 CharID, bool LFP);
void SetLFG(int32 CharID, bool LFG);
void AddReport(std::string who, std::string against, std::string lines);
protected:
void HandleMysqlError(int32 errnum);
//bool RunQuery(const char* query, int32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, int32* affected_rows = 0, int32* errnum = 0, bool retry = true);
private:
void DBInitVars();
int32 max_zonename;
char** zonename_array;
Mutex Mvarcache;
uint32 varcache_max;
VarCache_Struct** varcache_array;
uint32 varcache_lastupdate;
};
bool FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap);
#endif
|
|
|
|
04-17-2010, 08:35 PM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
For the record, the dual LS code was originally from Secrets. I haven't done anything at all with the LS code yet :P
|
04-17-2010, 08:52 PM
|
AX Classic Developer
|
|
Join Date: May 2006
Location: filler
Posts: 2,049
|
|
Thanks - now I know why I couldn't find the post!
|
04-17-2010, 10:29 PM
|
Developer
|
|
Join Date: Apr 2009
Location: USA
Posts: 478
|
|
It's the first portion of the muiltiple login server thread. I renamed it since it no longer was limited to dual login servers.
|
02-28-2014, 04:10 AM
|
Fire Beetle
|
|
Join Date: Feb 2007
Posts: 6
|
|
makering..............
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 11:13 AM.
|
|
|
|
|
|
|
|
|
|
|
|
|