mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase - All preliminary tests show things working great - All of player profile is saved and loaded from the database - DBAsync has been completely removed from all code - Removed zone/dbasync.cpp/.h - Removed common/dbasync.cpp/.h - Removed dbasync from cmake commmon and zone - Cleaned up a ton of functions - Added several tables to world CheckDatabaseConversions script: - `character_skills` - `character_languages` - `character_bind` - `character_alternate_abilities` - `character_currency` - `character_data` - `character_spells` - `character_memmed_spells` - `character_disciplines` - `character_material` - `character_tribute` - `character_bandolier` - `character_potionbelt` - Character select now loads from `character_data` - Character creation now creates to `character_data` - Updated function Database::UpdateName to use `character_data` - Updated function Database::CheckUsedName to use `character_data` - Updated function Database::MoveCharacterToZone to use `character_data` - Updated function Database::SetLoginFlags to use `character_data` - Updated function Database::SetFirstLogon to use `character_data` - Updated function Database::SetLFG to use `character_data` - Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with - Removed SharedDatabase::SetPlayerProfile - Trimmed down redundant case switch statements for World sendpackets to QueryServ - Added Character Methods to Database class: Loads: bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp); Saves: bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home); bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp); bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level); bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot); bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color); bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value); bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value); bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id); bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp); bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name); bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon); Deletes: bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id); bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
This commit is contained in:
parent
0a9222e1ee
commit
4432c07081
@ -8,7 +8,6 @@ SET(common_sources
|
||||
crc16.cpp
|
||||
crc32.cpp
|
||||
database.cpp
|
||||
dbasync.cpp
|
||||
dbcore.cpp
|
||||
debug.cpp
|
||||
emu_opcodes.cpp
|
||||
@ -103,7 +102,6 @@ SET(common_headers
|
||||
crc16.h
|
||||
crc32.h
|
||||
database.h
|
||||
dbasync.h
|
||||
dbcore.h
|
||||
debug.h
|
||||
deity.h
|
||||
|
||||
1354
common/database.cpp
1354
common/database.cpp
File diff suppressed because it is too large
Load Diff
@ -105,10 +105,16 @@ public:
|
||||
Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
~Database();
|
||||
bool ThrowDBError(std::string ErrorMessage, std::string query_title, std::string query);
|
||||
|
||||
|
||||
/*
|
||||
* General Character Related Stuff
|
||||
*/
|
||||
|
||||
/* Character Creation */
|
||||
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
|
||||
|
||||
bool MoveCharacterToZone(const char* charname, const char* zonename);
|
||||
bool MoveCharacterToZone(const char* charname, const char* zonename,uint32 zoneid);
|
||||
bool MoveCharacterToZone(uint32 iCharID, const char* iZonename);
|
||||
@ -118,16 +124,15 @@ public:
|
||||
bool AddToNameFilter(const char* name);
|
||||
bool ReserveName(uint32 account_id, char* name);
|
||||
bool CreateCharacter(uint32 account_id, char* name, uint16 gender, uint16 race, uint16 class_, uint8 str, uint8 sta, uint8 cha, uint8 dex, uint8 int_, uint8 agi, uint8 wis, uint8 face);
|
||||
bool StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext);
|
||||
bool StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv);
|
||||
bool DeleteCharacter(char* name);
|
||||
uint8 CopyCharacter(const char* oldname, const char* newname, uint32 acctid);
|
||||
|
||||
/*
|
||||
* General Information Getting Queries
|
||||
*/
|
||||
bool CheckNameFilter(const char* name, bool surname = false);
|
||||
bool CheckUsedName(const char* name);
|
||||
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
|
||||
uint32 GetAccountIDByChar(const char* charname);
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(const char* accname, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
@ -252,10 +257,6 @@ public:
|
||||
void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon);
|
||||
void AddReport(std::string who, std::string against, std::string lines);
|
||||
|
||||
|
||||
protected:
|
||||
void HandleMysqlError(uint32 errnum);
|
||||
|
||||
private:
|
||||
void DBInitVars();
|
||||
|
||||
|
||||
@ -1,669 +0,0 @@
|
||||
#include "debug.h"
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include "dbasync.h"
|
||||
#include "database.h"
|
||||
#include <errmsg.h>
|
||||
#include <mysqld_error.h>
|
||||
#include <limits.h>
|
||||
#include "dbcore.h"
|
||||
#include <string.h>
|
||||
//#include "../common/misc_functions.h"
|
||||
#include "string_util.h"
|
||||
#define ASYNC_LOOP_GRANULARITY 4 //# of ms between checking our work
|
||||
|
||||
bool DBAsyncCB_LoadVariables(DBAsyncWork* iWork) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* result = 0;
|
||||
DBAsyncQuery* dbaq = iWork->PopAnswer();
|
||||
if (dbaq->GetAnswer(errbuf, &result))
|
||||
iWork->GetDB()->LoadVariables_result(result);
|
||||
else
|
||||
std::cout << "Error: DBAsyncCB_LoadVariables failed: !GetAnswer: '" << errbuf << "'" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AsyncLoadVariables(DBAsync *dba, Database *db) {
|
||||
char* query = 0;
|
||||
DBAsyncWork* dbaw = new DBAsyncWork(db, &DBAsyncCB_LoadVariables, 0, DBAsync::Read);
|
||||
dbaw->AddQuery(0, &query, db->LoadVariables_MQ(&query));
|
||||
dba->AddWork(&dbaw);
|
||||
}
|
||||
|
||||
|
||||
//we only need to do anything when somebody puts work on the queue
|
||||
//so instead of checking all the time, we will wait on a condition
|
||||
//which will get signaled when somebody puts something on the queue
|
||||
ThreadReturnType DBAsyncLoop(void* tmp) {
|
||||
DBAsync* dba = (DBAsync*) tmp;
|
||||
|
||||
#ifndef WIN32
|
||||
_log(COMMON__THREADS, "Starting DBAsyncLoop with thread ID %d", pthread_self());
|
||||
#endif
|
||||
|
||||
dba->MLoopRunning.lock();
|
||||
while (dba->RunLoop()) {
|
||||
//wait before working so we check the loop condition
|
||||
//as soon as were done working
|
||||
dba->CInList.Wait();
|
||||
//we could check dba->RunLoop() again to see if we
|
||||
//got turned off while we were waiting
|
||||
{
|
||||
dba->Process();
|
||||
}
|
||||
}
|
||||
dba->MLoopRunning.unlock();
|
||||
|
||||
#ifndef WIN32
|
||||
_log(COMMON__THREADS, "Ending DBAsyncLoop with thread ID %d", pthread_self());
|
||||
#endif
|
||||
|
||||
THREAD_RETURN(nullptr);
|
||||
}
|
||||
|
||||
DBAsync::DBAsync(DBcore* iDBC)
|
||||
: Timeoutable(10000)
|
||||
{
|
||||
pDBC = iDBC;
|
||||
pRunLoop = true;
|
||||
pNextID = 1;
|
||||
#ifdef _WINDOWS
|
||||
_beginthread(DBAsyncLoop, 0, this);
|
||||
#else
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, DBAsyncLoop, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
DBAsync::~DBAsync() {
|
||||
StopThread();
|
||||
}
|
||||
|
||||
bool DBAsync::StopThread() {
|
||||
bool ret;
|
||||
MRunLoop.lock();
|
||||
ret = pRunLoop;
|
||||
pRunLoop = false;
|
||||
MRunLoop.unlock();
|
||||
|
||||
//signal the condition so we exit the loop if were waiting
|
||||
CInList.Signal();
|
||||
|
||||
//this effectively waits for the processing thread to finish
|
||||
MLoopRunning.lock();
|
||||
MLoopRunning.unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 DBAsync::AddWork(DBAsyncWork** iWork, uint32 iDelay) {
|
||||
MInList.lock();
|
||||
uint32 ret = GetNextID();
|
||||
if (!(*iWork)->SetWorkID(ret)) {
|
||||
MInList.unlock();
|
||||
return 0;
|
||||
}
|
||||
InList.Append(*iWork);
|
||||
(*iWork)->SetStatus(Queued);
|
||||
if (iDelay)
|
||||
(*iWork)->pExecuteAfter = Timer::GetCurrentTime() + iDelay;
|
||||
#if DEBUG_MYSQL_QUERIES >= 2
|
||||
std::cout << "Adding AsyncWork #" << (*iWork)->GetWorkID() << std::endl;
|
||||
std::cout << "ExecuteAfter = " << (*iWork)->pExecuteAfter << " (" << Timer::GetCurrentTime() << " + " << iDelay << ")" << std::endl;
|
||||
#endif
|
||||
*iWork = 0;
|
||||
MInList.unlock();
|
||||
|
||||
//wake up the processing thread and tell it to get to work.
|
||||
CInList.Signal();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsync::CancelWork(uint32 iWorkID) {
|
||||
if (iWorkID == 0)
|
||||
return false;
|
||||
#if DEBUG_MYSQL_QUERIES >= 2
|
||||
std::cout << "DBAsync::CancelWork: " << iWorkID << std::endl;
|
||||
#endif
|
||||
MCurrentWork.lock();
|
||||
if (CurrentWork && CurrentWork->GetWorkID() == iWorkID) {
|
||||
CurrentWork->Cancel();
|
||||
MCurrentWork.unlock();
|
||||
return true;
|
||||
}
|
||||
MCurrentWork.unlock();
|
||||
MInList.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(InList);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->GetWorkID() == iWorkID) {
|
||||
iterator.RemoveCurrent(true);
|
||||
MInList.unlock();
|
||||
return true;
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
MInList.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBAsync::RunLoop() {
|
||||
bool ret;
|
||||
MRunLoop.lock();
|
||||
ret = pRunLoop;
|
||||
MRunLoop.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncWork* DBAsync::InListPop() {
|
||||
DBAsyncWork* ret = 0;
|
||||
MInList.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(InList);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->pExecuteAfter <= Timer::GetCurrentTime()) {
|
||||
ret = iterator.GetData();
|
||||
#if DEBUG_MYSQL_QUERIES >= 2
|
||||
std::cout << "Poping AsyncWork #" << ret->GetWorkID() << std::endl;
|
||||
std::cout << ret->pExecuteAfter << " <= " << Timer::GetCurrentTime() << std::endl;
|
||||
#endif
|
||||
iterator.RemoveCurrent(false);
|
||||
break;
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
MInList.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncWork* DBAsync::InListPopWrite() {
|
||||
MInList.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(InList);
|
||||
|
||||
DBAsyncWork* ret = 0;
|
||||
DBAsync::Type tmpType;
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
tmpType = iterator.GetData()->Type();
|
||||
if (tmpType == Write || tmpType == Both) {
|
||||
ret = iterator.GetData();
|
||||
iterator.RemoveCurrent(false);
|
||||
break;
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
MInList.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DBAsync::AddFQ(DBAsyncFinishedQueue* iDBAFQ) {
|
||||
MFQList.lock();
|
||||
DBAsyncFinishedQueue** tmp = new DBAsyncFinishedQueue*;
|
||||
*tmp = iDBAFQ;
|
||||
FQList.Append(tmp);
|
||||
MFQList.unlock();
|
||||
}
|
||||
|
||||
void DBAsync::Process() {
|
||||
DBAsyncWork* tmpWork;
|
||||
MCurrentWork.lock();
|
||||
while ((CurrentWork = InListPop())) {
|
||||
MCurrentWork.unlock();
|
||||
//move from queued to executing
|
||||
Status tmpStatus = CurrentWork->SetStatus(Executing);
|
||||
if (tmpStatus == Queued) {
|
||||
//execute the work
|
||||
ProcessWork(CurrentWork);
|
||||
tmpWork = CurrentWork;
|
||||
MCurrentWork.lock();
|
||||
CurrentWork = 0;
|
||||
MCurrentWork.unlock();
|
||||
//move from executing to finished
|
||||
tmpStatus = tmpWork->SetStatus(DBAsync::Finished);
|
||||
if (tmpStatus != Executing) {
|
||||
if (tmpStatus != Canceled) {
|
||||
std::cout << "Error: Unexpected DBAsyncWork->Status in DBAsync::Process #1" << std::endl;
|
||||
}
|
||||
MCurrentWork.lock();
|
||||
safe_delete(tmpWork);
|
||||
}
|
||||
else {
|
||||
//call callbacks or put results on finished queue
|
||||
DispatchWork(tmpWork);
|
||||
Sleep(25);
|
||||
MCurrentWork.lock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tmpStatus != Canceled) {
|
||||
std::cout << "Error: Unexpected DBAsyncWork->Status in DBAsync::Process #2" << std::endl;
|
||||
}
|
||||
MCurrentWork.lock();
|
||||
safe_delete(CurrentWork);
|
||||
}
|
||||
}
|
||||
MCurrentWork.unlock();
|
||||
}
|
||||
|
||||
void DBAsync::CheckTimeout() {
|
||||
try{
|
||||
MFQList.lock();
|
||||
LinkedListIterator<DBAsyncFinishedQueue**> iterator(FQList);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
(*iterator.GetData())->CheckTimeouts();
|
||||
iterator.Advance();
|
||||
}
|
||||
MFQList.unlock();
|
||||
}
|
||||
catch(...){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DBAsync::CommitWrites() {
|
||||
#if DEBUG_MYSQL_QUERIES >= 2
|
||||
std::cout << "DBAsync::CommitWrites() called." << std::endl;
|
||||
#endif
|
||||
DBAsyncWork* tmpWork;
|
||||
while ((tmpWork = InListPopWrite())) {
|
||||
Status tmpStatus = tmpWork->SetStatus(Executing);
|
||||
if (tmpStatus == Queued) {
|
||||
ProcessWork(tmpWork);
|
||||
tmpStatus = tmpWork->SetStatus(DBAsync::Finished);
|
||||
if (tmpStatus != Executing) {
|
||||
if (tmpStatus != Canceled) {
|
||||
std::cout << "Error: Unexpected DBAsyncWork->Status in DBAsync::CommitWrites #1" << std::endl;
|
||||
}
|
||||
safe_delete(tmpWork);
|
||||
}
|
||||
else {
|
||||
DispatchWork(tmpWork);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tmpStatus != Canceled) {
|
||||
std::cout << "Error: Unexpected DBAsyncWork->Status in DBAsync::CommitWrites #2" << std::endl;
|
||||
}
|
||||
safe_delete(tmpWork);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DBAsync::ProcessWork(DBAsyncWork* iWork, bool iSleep) {
|
||||
DBAsyncQuery* CurrentQuery;
|
||||
while ((CurrentQuery = iWork->PopQuery())) {
|
||||
CurrentQuery->Process(pDBC);
|
||||
iWork->PushAnswer(CurrentQuery);
|
||||
if (iSleep)
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void DBAsync::DispatchWork(DBAsyncWork* iWork) {
|
||||
//if this work has a callback, call it
|
||||
//otherwise, stick the work on the finish queue
|
||||
if (iWork->pCB) {
|
||||
if (iWork->pCB(iWork))
|
||||
safe_delete(iWork);
|
||||
}
|
||||
else {
|
||||
if (!iWork->pDBAFQ->Push(iWork))
|
||||
safe_delete(iWork);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
DBAsyncFinishedQueue::DBAsyncFinishedQueue(uint32 iTimeout) {
|
||||
pTimeout = iTimeout;
|
||||
}
|
||||
|
||||
DBAsyncFinishedQueue::~DBAsyncFinishedQueue() {
|
||||
}
|
||||
|
||||
void DBAsyncFinishedQueue::CheckTimeouts() {
|
||||
if (pTimeout == 0xFFFFFFFF)
|
||||
return;
|
||||
MLock.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(list);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->CheckTimeout(pTimeout))
|
||||
iterator.RemoveCurrent(true);
|
||||
iterator.Advance();
|
||||
}
|
||||
MLock.unlock();
|
||||
}
|
||||
|
||||
DBAsyncWork* DBAsyncFinishedQueue::Pop() {
|
||||
DBAsyncWork* ret = 0;
|
||||
MLock.lock();
|
||||
ret = list.Pop();
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncWork* DBAsyncFinishedQueue::Find(uint32 iWorkID) {
|
||||
DBAsyncWork* ret = 0;
|
||||
MLock.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(list);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->GetWorkID() == iWorkID) {
|
||||
ret = iterator.GetData();
|
||||
iterator.RemoveCurrent(false);
|
||||
break;
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncWork* DBAsyncFinishedQueue::PopByWPT(uint32 iWPT) {
|
||||
DBAsyncWork* ret = 0;
|
||||
MLock.lock();
|
||||
LinkedListIterator<DBAsyncWork*> iterator(list);
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->WPT() == iWPT) {
|
||||
ret = iterator.GetData();
|
||||
iterator.RemoveCurrent(false);
|
||||
break;
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsyncFinishedQueue::Push(DBAsyncWork* iDBAW) {
|
||||
if (!this)
|
||||
return false;
|
||||
MLock.lock();
|
||||
list.Append(iDBAW);
|
||||
MLock.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DBAsyncWork::DBAsyncWork(Database *db, DBAsyncFinishedQueue* iDBAFQ, uint32 iWPT, DBAsync::Type iType, uint32 iTimeout)
|
||||
: m_db(db)
|
||||
{
|
||||
pstatus = DBAsync::AddingWork;
|
||||
pType = iType;
|
||||
pExecuteAfter = 0;
|
||||
pWorkID = 0;
|
||||
pDBAFQ = iDBAFQ;
|
||||
pCB = 0;
|
||||
pWPT = iWPT;
|
||||
pQuestionCount = 0;
|
||||
pAnswerCount = 0;
|
||||
pTimeout = iTimeout;
|
||||
pTSFinish = 0;
|
||||
}
|
||||
|
||||
DBAsyncWork::DBAsyncWork(Database *db, DBWorkCompleteCallBack iCB, uint32 iWPT, DBAsync::Type iType, uint32 iTimeout)
|
||||
: m_db(db)
|
||||
{
|
||||
pstatus = DBAsync::AddingWork;
|
||||
pType = iType;
|
||||
pExecuteAfter = 0;
|
||||
pWorkID = 0;
|
||||
pDBAFQ = 0;
|
||||
pCB = iCB;
|
||||
pWPT = iWPT;
|
||||
pQuestionCount = 0;
|
||||
pAnswerCount = 0;
|
||||
pTimeout = iTimeout;
|
||||
pTSFinish = 0;
|
||||
}
|
||||
|
||||
DBAsyncWork::~DBAsyncWork() {
|
||||
DBAsyncQuery* dbaq = 0;
|
||||
while ((dbaq = todo.pop()))
|
||||
safe_delete(dbaq);
|
||||
while ((dbaq = done.pop()))
|
||||
safe_delete(dbaq);
|
||||
while ((dbaq = todel.pop()))
|
||||
safe_delete(dbaq);
|
||||
}
|
||||
|
||||
bool DBAsyncWork::AddQuery(DBAsyncQuery** iDBAQ) {
|
||||
bool ret;
|
||||
MLock.lock();
|
||||
if (pstatus != DBAsync::AddingWork)
|
||||
ret = false;
|
||||
else {
|
||||
ret = true;
|
||||
pQuestionCount++;
|
||||
todo.push(*iDBAQ);
|
||||
(*iDBAQ)->pstatus = DBAsync::Queued;
|
||||
*iDBAQ = 0;
|
||||
}
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsyncWork::AddQuery(uint32 iQPT, char** iQuery, uint32 iQueryLen, bool iGetResultSet, bool iGetErrbuf) {
|
||||
DBAsyncQuery* DBAQ = new DBAsyncQuery(iQPT, iQuery, iQueryLen, iGetResultSet, iGetErrbuf);
|
||||
if (AddQuery(&DBAQ))
|
||||
return true;
|
||||
else {
|
||||
safe_delete(DBAQ);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBAsyncWork::SetWorkID(uint32 iWorkID) {
|
||||
bool ret = true;
|
||||
MLock.lock();
|
||||
if (pWorkID)
|
||||
ret = false;
|
||||
else
|
||||
pWorkID = iWorkID;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 DBAsyncWork::GetWorkID() {
|
||||
uint32 ret;
|
||||
MLock.lock();
|
||||
ret = pWorkID;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 DBAsyncWork::WPT() {
|
||||
uint32 ret;
|
||||
MLock.lock();
|
||||
ret = pWPT;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsync::Type DBAsyncWork::Type() {
|
||||
DBAsync::Type ret;
|
||||
MLock.lock();
|
||||
ret = pType;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncQuery* DBAsyncWork::PopAnswer() {
|
||||
DBAsyncQuery* ret;
|
||||
MLock.lock();
|
||||
ret = done.pop();
|
||||
if (ret)
|
||||
pAnswerCount--;
|
||||
todel.push(ret);
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsyncWork::CheckTimeout(uint32 iFQTimeout) {
|
||||
if (pTimeout == 0xFFFFFFFF)
|
||||
return false;
|
||||
bool ret = false;
|
||||
MLock.lock();
|
||||
if (pTimeout > iFQTimeout)
|
||||
iFQTimeout = pTimeout;
|
||||
if (Timer::GetCurrentTime() > (pTSFinish + iFQTimeout))
|
||||
ret = true;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
//sets the work's status to the supplied value and returns
|
||||
//the revious status
|
||||
DBAsync::Status DBAsyncWork::SetStatus(DBAsync::Status iStatus) {
|
||||
DBAsync::Status ret;
|
||||
MLock.lock();
|
||||
if (iStatus == DBAsync::Finished)
|
||||
pTSFinish = Timer::GetCurrentTime();
|
||||
ret = pstatus;
|
||||
pstatus = iStatus;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsyncWork::Cancel() {
|
||||
bool ret;
|
||||
MLock.lock();
|
||||
if (pstatus != DBAsync::Finished) {
|
||||
pstatus = DBAsync::Canceled;
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DBAsyncWork::IsCancled() {
|
||||
bool ret;
|
||||
MLock.lock();
|
||||
ret = (bool) (pstatus == DBAsync::Canceled);
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBAsyncQuery* DBAsyncWork::PopQuery() {
|
||||
DBAsyncQuery* ret = 0;
|
||||
MLock.lock();
|
||||
ret = todo.pop();
|
||||
if (ret)
|
||||
pQuestionCount--;
|
||||
MLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DBAsyncWork::PushAnswer(DBAsyncQuery* iDBAQ) {
|
||||
MLock.lock();
|
||||
done.push(iDBAQ);
|
||||
pAnswerCount++;
|
||||
MLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
DBAsyncQuery::DBAsyncQuery(uint32 iQPT, char** iQuery, uint32 iQueryLen, bool iGetResultSet, bool iGetErrbuf) {
|
||||
if (iQueryLen == 0xFFFFFFFF)
|
||||
pQueryLen = strlen(*iQuery);
|
||||
else
|
||||
pQueryLen = iQueryLen;
|
||||
pQuery = *iQuery;
|
||||
*iQuery = 0;
|
||||
Init(iQPT, iGetResultSet, iGetErrbuf);
|
||||
}
|
||||
|
||||
DBAsyncQuery::DBAsyncQuery(uint32 iQPT, const char* iQuery, uint32 iQueryLen, bool iGetResultSet, bool iGetErrbuf) {
|
||||
if (iQueryLen == 0xFFFFFFFF)
|
||||
pQueryLen = strlen(iQuery);
|
||||
else
|
||||
pQueryLen = iQueryLen;
|
||||
pQuery = strn0cpy(new char[pQueryLen+1], iQuery, pQueryLen+1);
|
||||
Init(iQPT, iGetResultSet, iGetErrbuf);
|
||||
}
|
||||
|
||||
void DBAsyncQuery::Init(uint32 iQPT, bool iGetResultSet, bool iGetErrbuf) {
|
||||
pstatus = DBAsync::AddingWork;
|
||||
pQPT = iQPT;
|
||||
pGetResultSet = iGetResultSet;
|
||||
pGetErrbuf = iGetErrbuf;
|
||||
|
||||
pmysqlsuccess = false;
|
||||
perrbuf = 0;
|
||||
perrnum = 0;
|
||||
presult = 0;
|
||||
paffected_rows = 0;
|
||||
plast_insert_id = 0;
|
||||
}
|
||||
|
||||
DBAsyncQuery::~DBAsyncQuery() {
|
||||
safe_delete_array(perrbuf);
|
||||
safe_delete_array(pQuery);
|
||||
if (presult)
|
||||
mysql_free_result(presult);
|
||||
}
|
||||
|
||||
bool DBAsyncQuery::GetAnswer(char* errbuf, MYSQL_RES** result, uint32* affected_rows, uint32* last_insert_id, uint32* errnum) {
|
||||
if (pstatus != DBAsync::Finished) {
|
||||
if (errbuf)
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "Error: Query not finished.");
|
||||
if (errnum)
|
||||
*errnum = UINT_MAX;
|
||||
return false;
|
||||
}
|
||||
if (errbuf) {
|
||||
if (pGetErrbuf) {
|
||||
if (perrbuf)
|
||||
strn0cpy(errbuf, perrbuf, MYSQL_ERRMSG_SIZE);
|
||||
else
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "Error message should've been saved, but hasnt. errno: %u", perrnum);
|
||||
}
|
||||
else
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "Error message not saved. errno: %u", perrnum);
|
||||
}
|
||||
if (errnum)
|
||||
*errnum = perrnum;
|
||||
if (affected_rows)
|
||||
*affected_rows = paffected_rows;
|
||||
if (last_insert_id)
|
||||
*last_insert_id = plast_insert_id;
|
||||
if (result)
|
||||
*result = presult;
|
||||
return pmysqlsuccess;
|
||||
}
|
||||
|
||||
void DBAsyncQuery::Process(DBcore* iDBC) {
|
||||
pstatus = DBAsync::Executing;
|
||||
if (pGetErrbuf)
|
||||
perrbuf = new char[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES** resultPP = 0;
|
||||
if (pGetResultSet)
|
||||
resultPP = &presult;
|
||||
pmysqlsuccess = iDBC->RunQuery(pQuery, pQueryLen, perrbuf, resultPP, &paffected_rows, &plast_insert_id, &perrnum);
|
||||
pstatus = DBAsync::Finished;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
176
common/dbasync.h
176
common/dbasync.h
@ -1,176 +0,0 @@
|
||||
#ifndef DBASYNC_H
|
||||
#define DBASYNC_H
|
||||
#include "../common/dbcore.h"
|
||||
#include "../common/timeoutmgr.h"
|
||||
|
||||
|
||||
class DBAsyncFinishedQueue;
|
||||
class DBAsyncWork;
|
||||
class DBAsyncQuery;
|
||||
class Database;
|
||||
|
||||
// Big daddy that owns the threads and does the work
|
||||
class DBAsync : private Timeoutable {
|
||||
public:
|
||||
enum Status { AddingWork, Queued, Executing, Finished, Canceled };
|
||||
enum Type { Read, Write, Both };
|
||||
|
||||
DBAsync(DBcore* iDBC);
|
||||
~DBAsync();
|
||||
bool StopThread();
|
||||
|
||||
uint32 AddWork(DBAsyncWork** iWork, uint32 iDelay = 0);
|
||||
bool CancelWork(uint32 iWorkID);
|
||||
void CommitWrites();
|
||||
|
||||
void AddFQ(DBAsyncFinishedQueue* iDBAFQ);
|
||||
protected:
|
||||
//things related to the processing thread:
|
||||
friend ThreadReturnType DBAsyncLoop(void* tmp);
|
||||
Mutex MLoopRunning;
|
||||
Condition CInList;
|
||||
bool RunLoop();
|
||||
void Process();
|
||||
|
||||
private:
|
||||
virtual void CheckTimeout();
|
||||
|
||||
void ProcessWork(DBAsyncWork* iWork, bool iSleep = true);
|
||||
void DispatchWork(DBAsyncWork* iWork);
|
||||
inline uint32 GetNextID() { return pNextID++; }
|
||||
DBAsyncWork* InListPop();
|
||||
DBAsyncWork* InListPopWrite(); // Ignores delay
|
||||
void OutListPush(DBAsyncWork* iDBAW);
|
||||
|
||||
Mutex MRunLoop;
|
||||
bool pRunLoop;
|
||||
|
||||
DBcore* pDBC;
|
||||
uint32 pNextID;
|
||||
Mutex MInList;
|
||||
LinkedList<DBAsyncWork*> InList;
|
||||
|
||||
Mutex MFQList;
|
||||
LinkedList<DBAsyncFinishedQueue**> FQList;
|
||||
|
||||
// Mutex for outside access to current work & when current work is being changed.
|
||||
// NOT locked when CurrentWork is being accessed by the DBAsync thread.
|
||||
// Never change pointer from outside DBAsync thread!
|
||||
// Only here for access to thread-safe DBAsyncWork functions.
|
||||
Mutex MCurrentWork;
|
||||
DBAsyncWork* CurrentWork;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
DB Work Complete Callback:
|
||||
This will be called under the DBAsync thread! Never access any non-threadsafe
|
||||
data/functions/classes. (ie: zone, entitylist, client, etc are not threadsafe)
|
||||
Function prototype:
|
||||
return value: true if we should delete the data, false if we should keep it
|
||||
*/
|
||||
typedef bool(*DBWorkCompleteCallBack)(DBAsyncWork*);
|
||||
|
||||
class DBAsyncFinishedQueue {
|
||||
public:
|
||||
DBAsyncFinishedQueue(uint32 iTimeout = 90000);
|
||||
~DBAsyncFinishedQueue();
|
||||
|
||||
DBAsyncWork* Pop();
|
||||
DBAsyncWork* PopByWPT(uint32 iWPT);
|
||||
DBAsyncWork* Find(uint32 iWPT);
|
||||
bool Push(DBAsyncWork* iDBAW);
|
||||
|
||||
void CheckTimeouts();
|
||||
private:
|
||||
Mutex MLock;
|
||||
uint32 pTimeout;
|
||||
LinkedList<DBAsyncWork*> list;
|
||||
};
|
||||
|
||||
// Container class for multiple queries
|
||||
class DBAsyncWork {
|
||||
public:
|
||||
DBAsyncWork(Database *db, DBAsyncFinishedQueue* iDBAFQ, uint32 iWPT = 0, DBAsync::Type iType = DBAsync::Both, uint32 iTimeout = 0);
|
||||
DBAsyncWork(Database *db, DBWorkCompleteCallBack iCB, uint32 iWPT = 0, DBAsync::Type iType = DBAsync::Both, uint32 iTimeout = 0);
|
||||
~DBAsyncWork();
|
||||
|
||||
bool AddQuery(DBAsyncQuery** iDBAQ);
|
||||
bool AddQuery(uint32 iQPT, char** iQuery, uint32 iQueryLen = 0xFFFFFFFF, bool iGetResultSet = true, bool iGetErrbuf = true);
|
||||
uint32 WPT();
|
||||
DBAsync::Type Type();
|
||||
|
||||
// Pops finished queries off the work
|
||||
DBAsyncQuery* PopAnswer();
|
||||
uint32 QueryCount();
|
||||
|
||||
Database *GetDB() const { return(m_db); }
|
||||
|
||||
bool CheckTimeout(uint32 iFQTimeout);
|
||||
bool SetWorkID(uint32 iWorkID);
|
||||
uint32 GetWorkID();
|
||||
protected:
|
||||
friend class DBAsync;
|
||||
DBAsync::Status SetStatus(DBAsync::Status iStatus);
|
||||
bool Cancel();
|
||||
bool IsCancled();
|
||||
DBAsyncQuery* PopQuery(); // Get query to be run
|
||||
void PushAnswer(DBAsyncQuery* iDBAQ); // Push answer back into workset
|
||||
|
||||
// not mutex'd cause only to be accessed from dbasync class
|
||||
uint32 pExecuteAfter;
|
||||
private:
|
||||
Mutex MLock;
|
||||
uint32 pQuestionCount;
|
||||
uint32 pAnswerCount;
|
||||
uint32 pWorkID;
|
||||
uint32 pWPT;
|
||||
uint32 pTimeout;
|
||||
uint32 pTSFinish; // timestamp when finished
|
||||
DBAsyncFinishedQueue* pDBAFQ; //we do now own this pointer
|
||||
DBWorkCompleteCallBack pCB;
|
||||
DBAsync::Status pstatus;
|
||||
DBAsync::Type pType;
|
||||
MyQueue<DBAsyncQuery> todo;
|
||||
MyQueue<DBAsyncQuery> done;
|
||||
MyQueue<DBAsyncQuery> todel;
|
||||
Database *const m_db; //we do now own this pointer
|
||||
};
|
||||
|
||||
// Container class for the query information
|
||||
class DBAsyncQuery {
|
||||
public:
|
||||
DBAsyncQuery(uint32 iQPT, char** iQuery, uint32 iQueryLen = 0xFFFFFFFF, bool iGetResultSet = true, bool iGetErrbuf = true);
|
||||
DBAsyncQuery(uint32 iQPT, const char* iQuery, uint32 iQueryLen = 0xFFFFFFFF, bool iGetResultSet = true, bool iGetErrbuf = true);
|
||||
~DBAsyncQuery();
|
||||
|
||||
bool GetAnswer(char* errbuf = 0, MYSQL_RES** result = 0, uint32* affected_rows = 0, uint32* last_insert_id = 0, uint32* errnum = 0);
|
||||
inline uint32 QPT() { return pQPT; }
|
||||
protected:
|
||||
friend class DBAsyncWork;
|
||||
uint32 pQPT;
|
||||
|
||||
friend class DBAsync;
|
||||
void Process(DBcore* iDBC);
|
||||
|
||||
void Init(uint32 iQPT, bool iGetResultSet, bool iGetErrbuf);
|
||||
DBAsync::Status pstatus;
|
||||
char* pQuery;
|
||||
uint32 pQueryLen;
|
||||
bool pGetResultSet;
|
||||
bool pGetErrbuf;
|
||||
|
||||
bool pmysqlsuccess;
|
||||
char* perrbuf;
|
||||
uint32 perrnum;
|
||||
uint32 paffected_rows;
|
||||
uint32 plast_insert_id;
|
||||
MYSQL_RES* presult;
|
||||
};
|
||||
|
||||
|
||||
void AsyncLoadVariables(DBAsync *dba, Database *db);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -800,9 +800,12 @@ struct SuspendedMinion_Struct
|
||||
** Length: 4308 bytes
|
||||
** OpCode: 0x006a
|
||||
*/
|
||||
static const uint32 MAX_PP_LANGUAGE = 28;
|
||||
static const uint32 MAX_PP_SPELLBOOK = 480; // Increased to 480 to support SoF
|
||||
static const uint32 MAX_PP_MEMSPELL = 9;
|
||||
static const uint32 MAX_PP_LANGUAGE = 28;
|
||||
static const uint32 MAX_PP_SPELLBOOK = 720; // Set for all functions
|
||||
static const uint32 MAX_PP_MEMSPELL = 12; // Set to latest client so functions can work right
|
||||
static const uint32 MAX_PP_REF_SPELLBOOK = 480; // Set for Player Profile size retain
|
||||
static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain
|
||||
|
||||
static const uint32 MAX_PP_SKILL = _SkillPacketArraySize; // 100 - actual skills buffer size
|
||||
static const uint32 MAX_PP_AA_ARRAY = 240;
|
||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||
@ -880,7 +883,7 @@ struct PlayerProfile_Struct
|
||||
/*0245*/ uint8 guildbanker;
|
||||
/*0246*/ uint8 unknown0246[6]; //
|
||||
/*0252*/ uint32 intoxication;
|
||||
/*0256*/ uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; //in ms
|
||||
/*0256*/ uint32 spellSlotRefresh[MAX_PP_REF_MEMSPELL]; //in ms
|
||||
/*0292*/ uint32 abilitySlotRefresh;
|
||||
/*0296*/ uint8 haircolor; // Player hair color
|
||||
/*0297*/ uint8 beardcolor; // Player beard color
|
||||
@ -919,9 +922,9 @@ struct PlayerProfile_Struct
|
||||
/*2505*/ uint8 unknown2541[47]; // ?
|
||||
/*2552*/ uint8 languages[MAX_PP_LANGUAGE];
|
||||
/*2580*/ uint8 unknown2616[4];
|
||||
/*2584*/ uint32 spell_book[MAX_PP_SPELLBOOK];
|
||||
/*2584*/ uint32 spell_book[MAX_PP_REF_SPELLBOOK];
|
||||
/*4504*/ uint8 unknown4540[128]; // Was [428] all 0xff
|
||||
/*4632*/ uint32 mem_spells[MAX_PP_MEMSPELL];
|
||||
/*4632*/ uint32 mem_spells[MAX_PP_REF_MEMSPELL];
|
||||
/*4668*/ uint8 unknown4704[32]; //
|
||||
/*4700*/ float y; // Player y position
|
||||
/*4704*/ float x; // Player x position
|
||||
|
||||
@ -32,6 +32,7 @@ MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, u
|
||||
|
||||
void MySQLRequestResult::FreeInternals()
|
||||
{
|
||||
|
||||
safe_delete_array(m_ErrorBuffer);
|
||||
|
||||
if (m_Result != nullptr)
|
||||
|
||||
@ -40,7 +40,7 @@ public:
|
||||
MySQLRequestResult& operator=(MySQLRequestResult&& other);
|
||||
|
||||
bool Success() const { return m_Success;}
|
||||
std::string ErrorMessage() const {return std::string(m_ErrorBuffer);}
|
||||
std::string ErrorMessage() const { return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string(""); }
|
||||
uint32 ErrorNumber() const {return m_ErrorNumber;}
|
||||
uint32 RowsAffected() const {return m_RowsAffected;}
|
||||
uint32 RowCount() const {return m_RowCount;}
|
||||
|
||||
@ -61,46 +61,6 @@ bool SharedDatabase::SetHideMe(uint32 account_id, uint8 hideme)
|
||||
return true;
|
||||
|
||||
}
|
||||
bool SharedDatabase::SetPlayerProfile(uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (RunQuery(query, SetPlayerProfile_MQ(&query, account_id, charid, pp, inv, ext, current_zone, current_instance, MaxXTargets), errbuf, 0, &affected_rows)) {
|
||||
ret = (affected_rows != 0);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
LogFile->write(EQEMuLog::Error, "SetPlayerProfile query '%s' %s", query, errbuf);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Generate SQL for updating player profile
|
||||
uint32 SharedDatabase::SetPlayerProfile_MQ(char** query, uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets) {
|
||||
*query = new char[396 + sizeof(PlayerProfile_Struct)* 2 + sizeof(ExtendedProfile_Struct)* 2 + 4];
|
||||
char* end = *query;
|
||||
if (!current_zone)
|
||||
current_zone = pp->zone_id;
|
||||
|
||||
if (!current_instance)
|
||||
current_instance = pp->zoneInstance;
|
||||
|
||||
if (strlen(pp->name) == 0) // Sanity check in case pp never loaded
|
||||
return false;
|
||||
|
||||
end += sprintf(end, "UPDATE character_ SET timelaston=unix_timestamp(now()),name=\'%s\', zonename=\'%s\', zoneid=%u, instanceid=%u, x = %f, y = %f, z = %f, ", pp->name, GetZoneName(current_zone), current_zone, current_instance, 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, "\',class=%d,level=%d,xtargets=%u WHERE id=%u", pp->class_, pp->level, MaxXTargets, charid);
|
||||
|
||||
return (uint32)(end - (*query));
|
||||
}
|
||||
|
||||
|
||||
uint8 SharedDatabase::GetGMSpeed(uint32 account_id)
|
||||
{
|
||||
@ -386,12 +346,11 @@ int32 SharedDatabase::GetSharedPlatinum(uint32 account_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add)
|
||||
{
|
||||
bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET sharedplat = sharedplat + %i WHERE id = %i", amount_to_add, account_id), errbuf)) {
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE `account` SET `sharedplat` = `sharedplat` + %i WHERE id = %i", amount_to_add, account_id), errbuf)) {
|
||||
std::cerr << "Error in SetSharedPlatinum query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return false;
|
||||
@ -401,35 +360,24 @@ bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) {
|
||||
const Item_Struct* myitem;
|
||||
|
||||
RunQuery
|
||||
(
|
||||
query,
|
||||
MakeAnyLenString
|
||||
(
|
||||
&query,
|
||||
"SELECT itemid, item_charges, slot FROM starting_items "
|
||||
"WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND "
|
||||
"(deityid = %i or deityid=0) AND (zoneid = %i or zoneid = 0) AND "
|
||||
"gm <= %i ORDER BY id",
|
||||
si_race, si_class, si_deity, si_current_zone, admin_level
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
);
|
||||
safe_delete_array(query);
|
||||
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
int itemid = atoi(row[0]);
|
||||
int charges = atoi(row[1]);
|
||||
int slot = atoi(row[2]);
|
||||
uint32 itemid = 0;
|
||||
uint32 charges = 0;
|
||||
uint32 slot = 0;
|
||||
auto query = StringFormat(
|
||||
"SELECT `itemid`, `item_charges`, `slot` FROM `starting_items`"
|
||||
" WHERE (`race` = %i OR `race` = 0)"
|
||||
" AND (`class` = %i OR `class` = 0)"
|
||||
" AND (`deityid` = %i OR `deityid` = 0)"
|
||||
" AND (`zoneid` = %i OR `zoneid` = 0)"
|
||||
" AND gm <= %i ORDER BY id",
|
||||
si_race, si_class, si_deity, si_current_zone, admin_level);
|
||||
auto results = QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
itemid = atoi(row[0]);
|
||||
charges = atoi(row[1]);
|
||||
slot = atoi(row[2]);
|
||||
myitem = GetItem(itemid);
|
||||
if(!myitem)
|
||||
continue;
|
||||
@ -439,9 +387,6 @@ bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv,
|
||||
inv->PutItem(slot, *myinst);
|
||||
safe_delete(myinst);
|
||||
}
|
||||
|
||||
if(result) mysql_free_result(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -675,8 +620,13 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
|
||||
bool ret = false;
|
||||
|
||||
// Retrieve character inventory
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT slotid,itemid,charges,color,augslot1,augslot2,augslot3,augslot4,augslot5,"
|
||||
"instnodrop,custom_data FROM inventory INNER JOIN character_ ch ON ch.id=charid WHERE ch.name='%s' AND ch.account_id=%i ORDER BY slotid",
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
" SELECT `slotid`, `itemid`, `charges`, `color`, `augslot1`, `augslot2`, `augslot3`, `augslot4`, `augslot5`, `instnodrop`, `custom_data`"
|
||||
" FROM `inventory`"
|
||||
" INNER JOIN character_ ch ON ch.id = charid"
|
||||
" WHERE ch.NAME = '%s'"
|
||||
" AND ch.account_id = % i"
|
||||
" ORDER BY `slotid`",
|
||||
name, account_id), errbuf, &result))
|
||||
{
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
@ -736,7 +686,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (slot_id>=8000 && slot_id <= 8999)
|
||||
if (slot_id >= 8000 && slot_id <= 8999)
|
||||
put_slot_id = inv->PushCursor(*inst);
|
||||
else
|
||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||
@ -2053,8 +2003,7 @@ const LootDrop_Struct* SharedDatabase::GetLootDrop(uint32 lootdrop_id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SharedDatabase::GetPlayerInspectMessage(char* playername, InspectMessage_Struct* message) {
|
||||
|
||||
void SharedDatabase::GetPlayerInspectMessage(char* playername, InspectMessage_Struct* message) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
|
||||
@ -34,9 +34,6 @@ public:
|
||||
SharedDatabase(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
virtual ~SharedDatabase();
|
||||
|
||||
/* Temp */
|
||||
uint32 SetPlayerProfile_MQ(char** query, uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets);
|
||||
bool SetPlayerProfile(uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets);
|
||||
/*
|
||||
* General Character Related Stuff
|
||||
*/
|
||||
|
||||
161
world/client.cpp
161
world/client.cpp
@ -64,8 +64,6 @@ 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)),
|
||||
@ -128,9 +126,8 @@ void Client::SendLogServer()
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SendEnterWorld(std::string name)
|
||||
{
|
||||
char char_name[32]= { 0 };
|
||||
void Client::SendEnterWorld(std::string name) {
|
||||
char char_name[32]= { 0 };
|
||||
if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) {
|
||||
if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
|
||||
eqs->Close();
|
||||
@ -472,7 +469,6 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) {
|
||||
|
||||
if (GetAccountID() == 0) {
|
||||
clog(WORLD__CLIENT_ERR,"Name approval request with no logged in account");
|
||||
return false;
|
||||
@ -491,19 +487,10 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) {
|
||||
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;
|
||||
}
|
||||
if(!database.CheckNameFilter(char_name)) { valid = false; }
|
||||
else if (char_name[0] < 'A' && char_name[0] > 'Z') { valid = false; } /* Name must begin with an upper-case letter. */
|
||||
else if (database.ReserveName(GetAccountID(), char_name)) { valid = true; }
|
||||
else { valid = false; }
|
||||
outapp->pBuffer[0] = valid? 1 : 0;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
@ -642,13 +629,11 @@ bool Client::HandleCharacterCreateRequestPacket(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
||||
if (GetAccountID() == 0)
|
||||
{
|
||||
if (GetAccountID() == 0) {
|
||||
clog(WORLD__CLIENT_ERR,"Account ID not set; unable to create character.");
|
||||
return false;
|
||||
}
|
||||
else if (app->size != sizeof(CharCreate_Struct))
|
||||
{
|
||||
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);
|
||||
// the previous behavior was essentially returning true here
|
||||
@ -657,8 +642,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
CharCreate_Struct *cc = (CharCreate_Struct*)app->pBuffer;
|
||||
if(OPCharCreate(char_name, cc) == false)
|
||||
{
|
||||
if(OPCharCreate(char_name, cc) == false) {
|
||||
database.DeleteCharacter(char_name);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ApproveName, 1);
|
||||
outapp->pBuffer[0] = 0;
|
||||
@ -675,8 +659,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
|
||||
bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
if (GetAccountID() == 0) {
|
||||
clog(WORLD__CLIENT_ERR,"Enter world with no logged in account");
|
||||
eqs->Close();
|
||||
@ -713,8 +696,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!pZoning && ew->return_home && !ew->tutorial)
|
||||
{
|
||||
if(!pZoning && ew->return_home && !ew->tutorial) {
|
||||
CharacterSelect_Struct* cs = new CharacterSelect_Struct;
|
||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
||||
database.GetCharSelectInfo(GetAccountID(), cs);
|
||||
@ -733,12 +715,10 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
safe_delete(cs);
|
||||
|
||||
if(home_enabled)
|
||||
{
|
||||
if(home_enabled) {
|
||||
zoneID = database.MoveCharacterToBind(charid,4);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 go home before they were able.");
|
||||
eqs->Close();
|
||||
@ -807,16 +787,16 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
database.SetLoginFlags(charid, false, false, 1);
|
||||
}
|
||||
else{
|
||||
uint32 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){
|
||||
uint32 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);
|
||||
strcpy(gj->yourname, char_name);
|
||||
strcpy(gj->membername, leader);
|
||||
QueuePacket(outapp3);
|
||||
safe_delete(outapp3);
|
||||
}
|
||||
@ -895,8 +875,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) {
|
||||
|
||||
uint32 char_acct_id = database.GetAccountIDByChar((char*)app->pBuffer);
|
||||
if(char_acct_id == GetAccountID())
|
||||
{
|
||||
if(char_acct_id == GetAccountID()) {
|
||||
clog(WORLD__CLIENT,"Delete character: %s",app->pBuffer);
|
||||
database.DeleteCharacter((char *)app->pBuffer);
|
||||
SendCharInfo();
|
||||
@ -1347,8 +1326,7 @@ void Client::SendApproveWorld()
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
{
|
||||
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) {
|
||||
PlayerProfile_Struct pp;
|
||||
ExtendedProfile_Struct ext;
|
||||
Inventory inv;
|
||||
@ -1356,12 +1334,11 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
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;
|
||||
|
||||
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",
|
||||
@ -1374,38 +1351,23 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
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
|
||||
/* Validate the char creation struct */
|
||||
if(ClientVersionBit & BIT_SoFAndLater) {
|
||||
if(!CheckCharCreateInfoSoF(cc))
|
||||
{
|
||||
if(!CheckCharCreateInfoSoF(cc)) {
|
||||
clog(WORLD__CLIENT_ERR,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(!CheckCharCreateInfoTitanium(cc))
|
||||
{
|
||||
if(!CheckCharCreateInfoTitanium(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
|
||||
/* Convert incoming cc_s to the new PlayerProfile_Struct */
|
||||
memset(&pp, 0, sizeof(PlayerProfile_Struct)); // start building the profile
|
||||
|
||||
InitExtendedProfile(&ext);
|
||||
|
||||
strn0cpy(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_;
|
||||
@ -1432,44 +1394,39 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
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.cur_hp = 1000; // 1k hp during dev only
|
||||
pp.hunger_level = 6000;
|
||||
pp.thirst_level = 6000;
|
||||
|
||||
|
||||
// FIXME: FV roleplay, database goodness...
|
||||
|
||||
// Racial Languages
|
||||
SetRacialLanguages( &pp ); // bUsh
|
||||
SetRaceStartingSkills( &pp ); // bUsh
|
||||
SetClassStartingSkills( &pp ); // bUsh
|
||||
/* Racial Languages */
|
||||
SetRacialLanguages( &pp );
|
||||
SetRaceStartingSkills( &pp );
|
||||
SetClassStartingSkills( &pp );
|
||||
pp.skills[SkillSenseHeading] = 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++)
|
||||
for (i = 0; i < MAX_PP_REF_SPELLBOOK; i++)
|
||||
pp.spell_book[i] = 0xFFFFFFFF;
|
||||
|
||||
for(i = 0; i < MAX_PP_MEMSPELL; i++)
|
||||
for(i = 0; i < MAX_PP_REF_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
|
||||
*/
|
||||
|
||||
//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.
|
||||
/* 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 it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
||||
if((ClientVersionBit & BIT_SoFAndLater) && (RuleI(World, SoFStartZoneID) > 0)) {
|
||||
clog(WORLD__CLIENT,"Found 'SoFStartZoneID' rule setting: %i", (RuleI(World, SoFStartZoneID)));
|
||||
pp.zone_id = (RuleI(World, SoFStartZoneID));
|
||||
@ -1478,11 +1435,9 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
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))
|
||||
{
|
||||
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)
|
||||
@ -1490,8 +1445,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
else
|
||||
clog(WORLD__CLIENT_ERR,"Error getting zone id for '%s'", startzone);
|
||||
}
|
||||
else // otherwise use normal starting zone logic
|
||||
{
|
||||
else{ /* otherwise use normal starting zone logic */
|
||||
bool ValidStartZone = false;
|
||||
|
||||
if(ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||
@ -1504,14 +1458,12 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
}
|
||||
}
|
||||
|
||||
if(!pp.zone_id)
|
||||
{
|
||||
if(!pp.zone_id) {
|
||||
pp.zone_id = 1; // qeynos
|
||||
pp.x = pp.y = pp.z = -1;
|
||||
}
|
||||
|
||||
if(!pp.binds[0].zoneId)
|
||||
{
|
||||
if(!pp.binds[0].zoneId) {
|
||||
pp.binds[0].zoneId = pp.zone_id;
|
||||
pp.binds[0].x = pp.x;
|
||||
pp.binds[0].y = pp.y;
|
||||
@ -1519,7 +1471,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
pp.binds[0].heading = pp.heading;
|
||||
}
|
||||
|
||||
// set starting city location to the initial bind point
|
||||
/* Set Starting city */
|
||||
pp.binds[4] = pp.binds[0];
|
||||
|
||||
|
||||
@ -1528,28 +1480,23 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
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
|
||||
/* 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))
|
||||
{
|
||||
if (!database.StoreCharacter(GetAccountID(), &pp, &inv)) {
|
||||
clog(WORLD__CLIENT_ERR,"Character creation failed: %s", pp.name);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 CheckCharCreateInfoSoF(CharCreate_Struct *cc)
|
||||
{
|
||||
bool CheckCharCreateInfoSoF(CharCreate_Struct *cc) {
|
||||
if(!cc) return false;
|
||||
|
||||
_log(WORLD__CLIENT, "Validating char creation info...");
|
||||
|
||||
@ -67,7 +67,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include "../common/dbasync.h"
|
||||
#include "../common/emu_tcp_server.h"
|
||||
#include "../common/patches/patches.h"
|
||||
#include "zoneserver.h"
|
||||
@ -98,7 +97,6 @@ UCSConnection UCSLink;
|
||||
QueryServConnection QSLink;
|
||||
LauncherList launcher_list;
|
||||
AdventureManager adventure_manager;
|
||||
DBAsync *dbasync = nullptr;
|
||||
volatile bool RunLoops = true;
|
||||
uint32 numclients = 0;
|
||||
uint32 numzones = 0;
|
||||
@ -175,7 +173,6 @@ int main(int argc, char** argv) {
|
||||
_log(WORLD__INIT_ERR, "Cannot continue without a database connection.");
|
||||
return 1;
|
||||
}
|
||||
dbasync = new DBAsync(&database);
|
||||
guild_mgr.SetDatabase(&database);
|
||||
|
||||
if (argc >= 2) {
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/item.h"
|
||||
#include "../common/dbasync.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
@ -390,12 +389,16 @@ bool WorldDatabase::GetStartZoneSoF(PlayerProfile_Struct* in_pp, CharCreate_Stru
|
||||
in_pp->x = in_pp->y = in_pp->z = in_pp->heading = in_pp->zone_id = 0;
|
||||
in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = 0;
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "SELECT x,y,z,heading,bind_id FROM start_zones WHERE zone_id=%i AND player_class=%i "
|
||||
"AND player_deity=%i AND player_race=%i",
|
||||
in_cc->start_zone,
|
||||
in_cc->class_,
|
||||
in_cc->deity,
|
||||
in_cc->race), errbuf, &result))
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "SELECT `x`, `y`, ``z, `heading`, `bind_id` "
|
||||
" FROM `start_zones` "
|
||||
" WHERE `zone_id` = %i "
|
||||
" AND `player_class` = %i "
|
||||
" AND player_deity=%i"
|
||||
" AND player_race=%i",
|
||||
in_cc->start_zone,
|
||||
in_cc->class_,
|
||||
in_cc->deity,
|
||||
in_cc->race), errbuf, &result))
|
||||
{
|
||||
LogFile->write(EQEMuLog::Status, "SoF Start zone query failed: %s : %s\n", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
|
||||
@ -652,17 +652,17 @@ bool ZoneServer::Process() {
|
||||
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.
|
||||
//
|
||||
//
|
||||
// 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))
|
||||
@ -675,43 +675,31 @@ bool ZoneServer::Process() {
|
||||
zlog(WORLD__ZONE,"ZoneToZone request for %s current zone %d req zone %d\n",
|
||||
ztz->name, ztz->current_zone_id, ztz->requested_zone_id);
|
||||
|
||||
printf("\n\n ZoneToZone request for %s current zone %d req zone %d\n\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
|
||||
{
|
||||
/* This is a request from the egress zone */
|
||||
if(GetZoneID() == ztz->current_zone_id && GetInstanceID() == ztz->current_instance_id) {
|
||||
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)
|
||||
)
|
||||
{
|
||||
if (ztz->admin < 80 && ztz->ignorerestrictions < 2 && zoneserver_list.IsZoneLocked(ztz->requested_zone_id)) {
|
||||
ztz->response = 0;
|
||||
SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
|
||||
ZoneServer *ingress_server = nullptr;
|
||||
if(ztz->requested_instance_id > 0)
|
||||
{
|
||||
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);
|
||||
|
||||
else {
|
||||
ingress_server = zoneserver_list.FindByZoneID(ztz->requested_zone_id);
|
||||
}
|
||||
|
||||
if(ingress_server) // found a zone already running
|
||||
{
|
||||
/* Zone was already running*/
|
||||
if(ingress_server) {
|
||||
_log(WORLD__ZONE,"Found a zone already booted for %s\n", ztz->name);
|
||||
ztz->response = 1;
|
||||
}
|
||||
else // need to boot one
|
||||
{
|
||||
/* Boot the Zone*/
|
||||
else {
|
||||
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);
|
||||
@ -719,8 +707,7 @@ bool ZoneServer::Process() {
|
||||
ztz->response = 1;
|
||||
ingress_server = zoneserver_list.FindByID(server_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
@ -728,27 +715,24 @@ bool ZoneServer::Process() {
|
||||
}
|
||||
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
|
||||
}
|
||||
SendPacket(pack); // send back to egress server
|
||||
if(ingress_server) {
|
||||
ingress_server->SendPacket(pack); // inform target server
|
||||
}
|
||||
}
|
||||
else // this is response from the ingress server, route it back to the egress server
|
||||
{
|
||||
/* Response from Ingress server, route back to egress */
|
||||
else{
|
||||
|
||||
zlog(WORLD__ZONE,"Processing ZTZ for ingress to zone for client %s\n", ztz->name);
|
||||
ZoneServer *egress_server = nullptr;
|
||||
if(ztz->current_instance_id > 0)
|
||||
{
|
||||
if(ztz->current_instance_id > 0) {
|
||||
egress_server = zoneserver_list.FindByInstanceID(ztz->current_instance_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
egress_server = zoneserver_list.FindByZoneID(ztz->current_zone_id);
|
||||
}
|
||||
|
||||
if(egress_server)
|
||||
{
|
||||
if(egress_server) {
|
||||
egress_server->SendPacket(pack);
|
||||
}
|
||||
}
|
||||
@ -786,21 +770,18 @@ bool ZoneServer::Process() {
|
||||
delete whom;
|
||||
break;
|
||||
}
|
||||
case ServerOP_RequestOnlineGuildMembers:
|
||||
{
|
||||
case ServerOP_RequestOnlineGuildMembers: {
|
||||
ServerRequestOnlineGuildMembers_Struct *srogms = (ServerRequestOnlineGuildMembers_Struct*) pack->pBuffer;
|
||||
zlog(GUILDS__IN_PACKETS, "ServerOP_RequestOnlineGuildMembers Recieved. FromID=%i GuildID=%i", srogms->FromID, srogms->GuildID);
|
||||
client_list.SendOnlineGuildMembers(srogms->FromID, srogms->GuildID);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ClientVersionSummary:
|
||||
{
|
||||
case ServerOP_ClientVersionSummary: {
|
||||
ServerRequestClientVersionSummary_Struct *srcvss = (ServerRequestClientVersionSummary_Struct*) pack->pBuffer;
|
||||
client_list.SendClientVersionSummary(srcvss->Name);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadRules:
|
||||
{
|
||||
case ServerOP_ReloadRules: {
|
||||
zoneserver_list.SendPacket(pack);
|
||||
RuleManager::Instance()->LoadRules(&database, "default");
|
||||
break;
|
||||
@ -1275,30 +1256,10 @@ bool ZoneServer::Process() {
|
||||
case ServerOP_QueryServGeneric:
|
||||
case ServerOP_Speech:
|
||||
case ServerOP_QSPlayerLogTrades:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogHandins:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogNPCKills:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogDeletes:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMoves:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogMerchantTransactions:
|
||||
{
|
||||
QSLink.SendPacket(pack);
|
||||
|
||||
@ -119,7 +119,6 @@ SET(zone_sources
|
||||
zone_logsys.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zonedbasync.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
|
||||
@ -207,7 +206,6 @@ SET(zone_headers
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedbasync.h
|
||||
zonedump.h
|
||||
)
|
||||
|
||||
|
||||
@ -73,8 +73,6 @@ extern uint32 numclients;
|
||||
extern PetitionList petition_list;
|
||||
bool commandlogged;
|
||||
char entirecommand[255];
|
||||
extern DBAsyncFinishedQueue MTdbafq;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
Client::Client(EQStreamInterface* ieqs)
|
||||
: Mob("No name", // name
|
||||
@ -544,8 +542,9 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
/* Save Character Currency */
|
||||
database.SaveCharacterCurrency(this->CharacterID(), &m_pp);
|
||||
|
||||
/* Save Character AA */
|
||||
// SaveAA();
|
||||
/* Save Current Bind Points : Sets Instance to 0 because it is currently not implemented */
|
||||
database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, 0, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0); /* Regular bind */
|
||||
database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[4].zoneId, 0, m_pp.binds[4].x, m_pp.binds[4].y, m_pp.binds[4].z, 0, 1); /* Home Bind */
|
||||
|
||||
/* Save Character Buffs */
|
||||
database.SaveBuffs(this);
|
||||
@ -557,15 +556,11 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
|
||||
/* Save Mercs */
|
||||
if (GetMercInfo().MercTimerRemaining > RuleI(Mercs, UpkeepIntervalMS)){ GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); }
|
||||
if(GetMercTimer()->Enabled()) { GetMercInfo().MercTimerRemaining = GetMercTimer()->GetRemainingTime(); }
|
||||
if (GetMercTimer()->Enabled()) { GetMercInfo().MercTimerRemaining = GetMercTimer()->GetRemainingTime(); }
|
||||
if (GetMerc() && !dead) { }
|
||||
else { memset(&m_mercinfo, 0, sizeof(struct MercInfo)); }
|
||||
|
||||
m_pp.lastlogin = time(nullptr);
|
||||
if (pQueuedSaveWorkID) {
|
||||
dbasync->CancelWork(pQueuedSaveWorkID);
|
||||
pQueuedSaveWorkID = 0;
|
||||
}
|
||||
|
||||
if (GetPet() && !GetPet()->IsFamiliar() && GetPet()->CastToNPC()->GetPetSpellID() && !dead) {
|
||||
NPC *pet = GetPet()->CastToNPC();
|
||||
@ -585,34 +580,10 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
|
||||
p_timers.Store(&database);
|
||||
|
||||
/* Save Character Task */
|
||||
SaveTaskState();
|
||||
database.SaveCharacterTribute(this->CharacterID(), &m_pp);
|
||||
|
||||
// if (iCommitNow <= 1) {
|
||||
// // char* query = 0;
|
||||
// // uint32_breakdown workpt;
|
||||
// // workpt.b4() = DBA_b4_Entity;
|
||||
// // workpt.w2_3() = GetID();
|
||||
// // workpt.b1() = DBA_b1_Entity_Client_Save;
|
||||
// // DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Write, 0xFFFFFFFF);
|
||||
// // dbaw->AddQuery(iCommitNow == 0 ? true : false, &query, database.SetPlayerProfile_MQ(&query, account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets), false);
|
||||
// // if (iCommitNow == 0){
|
||||
// // pQueuedSaveWorkID = dbasync->AddWork(&dbaw, 2500);
|
||||
// // }
|
||||
// // else {
|
||||
// // dbasync->AddWork(&dbaw, 0);
|
||||
// // SaveBackup();
|
||||
// // }
|
||||
// // safe_delete_array(query);
|
||||
// // return true;
|
||||
// }
|
||||
// else if (database.SetPlayerProfile(account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets)) {
|
||||
// SaveBackup();
|
||||
// }
|
||||
// else {
|
||||
// std::cerr << "Failed to update player profile" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
/* Save Character Task */
|
||||
SaveTaskState();
|
||||
|
||||
/* Save Character Data */
|
||||
database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp);
|
||||
@ -624,12 +595,6 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
}
|
||||
|
||||
void Client::SaveBackup() {
|
||||
if (!RunLoops)
|
||||
return;
|
||||
char* query = 0;
|
||||
DBAsyncWork* dbaw = new DBAsyncWork(&database, &DBAsyncCB_CharacterBackup, this->CharacterID(), DBAsync::Read);
|
||||
dbaw->AddQuery(0, &query, MakeAnyLenString(&query, "Select id, UNIX_TIMESTAMP()-UNIX_TIMESTAMP(ts) as age from character_backup where charid=%u and backupreason=0 order by ts asc", this->CharacterID()), true);
|
||||
dbasync->AddWork(&dbaw, 0);
|
||||
}
|
||||
|
||||
CLIENTPACKET::CLIENTPACKET()
|
||||
@ -1393,12 +1358,14 @@ bool Client::UpdateLDoNPoints(int32 points, uint32 theme)
|
||||
|
||||
void Client::SetSkill(SkillUseTypes skillid, uint16 value) {
|
||||
if (skillid > HIGHEST_SKILL)
|
||||
return;
|
||||
m_pp.skills[skillid] = value; // We need to be able to #setskill 254 and 255 to reset skills
|
||||
return;
|
||||
m_pp.skills[skillid] = value; // We need to be able to #setskill 254 and 255 to reset skills
|
||||
|
||||
database.SaveCharacterSkill(this->CharacterID(), skillid, value);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct));
|
||||
SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer;
|
||||
skill->skillId=skillid;
|
||||
skill->skillId=skillid;
|
||||
skill->value=value;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
@ -1414,10 +1381,12 @@ void Client::IncreaseLanguageSkill(int skill_id, int value) {
|
||||
if (m_pp.languages[skill_id] > 100) //Lang skill above max
|
||||
m_pp.languages[skill_id] = 100;
|
||||
|
||||
database.SaveCharacterLanguage(this->CharacterID(), skill_id, m_pp.languages[skill_id]);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct));
|
||||
SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer;
|
||||
skill->skillId = 100 + skill_id;
|
||||
skill->value = m_pp.languages[skill_id];
|
||||
skill->value = m_pp.languages[skill_id];
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
@ -2165,32 +2134,27 @@ void Client::AddMoneyToPP(uint64 copper, bool updateclient){
|
||||
uint64 tmp2;
|
||||
tmp = copper;
|
||||
|
||||
// Add Amount of Platinum
|
||||
/* Add Amount of Platinum */
|
||||
tmp2 = tmp/1000;
|
||||
int32 new_val = m_pp.platinum + tmp2;
|
||||
if(new_val < 0) {
|
||||
m_pp.platinum = 0;
|
||||
} else {
|
||||
m_pp.platinum = m_pp.platinum + tmp2;
|
||||
}
|
||||
if(new_val < 0) { m_pp.platinum = 0; }
|
||||
else { m_pp.platinum = m_pp.platinum + tmp2; }
|
||||
tmp-=tmp2*1000;
|
||||
|
||||
//if (updateclient)
|
||||
// SendClientMoneyUpdate(3,tmp2);
|
||||
|
||||
// Add Amount of Gold
|
||||
/* Add Amount of Gold */
|
||||
tmp2 = tmp/100;
|
||||
new_val = m_pp.gold + tmp2;
|
||||
if(new_val < 0) {
|
||||
m_pp.gold = 0;
|
||||
} else {
|
||||
m_pp.gold = m_pp.gold + tmp2;
|
||||
}
|
||||
if(new_val < 0) { m_pp.gold = 0; }
|
||||
else { m_pp.gold = m_pp.gold + tmp2; }
|
||||
|
||||
tmp-=tmp2*100;
|
||||
//if (updateclient)
|
||||
// SendClientMoneyUpdate(2,tmp2);
|
||||
|
||||
// Add Amount of Silver
|
||||
/* Add Amount of Silver */
|
||||
tmp2 = tmp/10;
|
||||
new_val = m_pp.silver + tmp2;
|
||||
if(new_val < 0) {
|
||||
@ -2226,8 +2190,7 @@ void Client::AddMoneyToPP(uint64 copper, bool updateclient){
|
||||
LogFile->write(EQEMuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i", GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
|
||||
}
|
||||
|
||||
void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool updateclient){
|
||||
|
||||
void Client::EVENT_ITEM_ScriptStopReturn(){
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
@ -2236,6 +2199,10 @@ void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 plat
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
}
|
||||
|
||||
void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool updateclient){
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
int32 new_value = m_pp.platinum + platinum;
|
||||
if(new_value >= 0 && new_value > m_pp.platinum)
|
||||
@ -3184,6 +3151,7 @@ void Client::SetLanguageSkill(int langid, int value)
|
||||
value = 100; //Max lang value
|
||||
|
||||
m_pp.languages[langid] = value;
|
||||
database.SaveCharacterLanguage(this->CharacterID(), langid, value);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct));
|
||||
SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
@ -234,7 +234,6 @@ public:
|
||||
bool KeyRingCheck(uint32 item_id);
|
||||
void KeyRingList();
|
||||
virtual bool IsClient() const { return true; }
|
||||
virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw);
|
||||
void CompleteConnect();
|
||||
bool TryStacking(ItemInst* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||
@ -654,14 +653,14 @@ public:
|
||||
|
||||
void OnDisconnect(bool hard_disconnect);
|
||||
|
||||
uint16 GetSkillPoints() {return m_pp.points;}
|
||||
void SetSkillPoints(int inp) {m_pp.points = inp;}
|
||||
uint16 GetSkillPoints() { return m_pp.points;}
|
||||
void SetSkillPoints(int inp) { m_pp.points = inp;}
|
||||
|
||||
void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } }
|
||||
void IncreaseLanguageSkill(int skill_id, int value = 1);
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0)? m_pp.skills[skill_id]*(100 + itembonuses.skillmod[skill_id])/100 : m_pp.skills[skill_id]); } return 0; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; }
|
||||
uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; }
|
||||
bool HasSkill(SkillUseTypes skill_id) const;
|
||||
bool HasSkill(SkillUseTypes skill_id) const;
|
||||
bool CanHaveSkill(SkillUseTypes skill_id) const;
|
||||
void SetSkill(SkillUseTypes skill_num, uint16 value);
|
||||
void AddSkill(SkillUseTypes skillid, uint16 value);
|
||||
@ -782,6 +781,7 @@ public:
|
||||
int16 acmod();
|
||||
|
||||
// Item methods
|
||||
void EVENT_ITEM_ScriptStopReturn();
|
||||
uint32 NukeItem(uint32 itemnum, uint8 where_to_check =
|
||||
(invWhereWorn | invWherePersonal | invWhereBank | invWhereSharedBank | invWhereTrading | invWhereCursor));
|
||||
void SetTint(int16 slot_id, uint32 color);
|
||||
|
||||
@ -77,9 +77,6 @@ extern volatile bool ZoneLoaded;
|
||||
extern WorldServer worldserver;
|
||||
extern PetitionList petition_list;
|
||||
extern EntityList entity_list;
|
||||
extern DBAsyncFinishedQueue MTdbafq;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
typedef void (Client::*ClientPacketProc)(const EQApplicationPacket *app);
|
||||
|
||||
//Use a map for connecting opcodes since it dosent get used a lot and is sparse
|
||||
@ -525,7 +522,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
client_state = CLIENT_KICKED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
strcpy(name, cze->char_name);
|
||||
/* Check for Client Spoofing */
|
||||
@ -592,19 +588,20 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if (LFG){ LFG = atoi(row[12]); }
|
||||
if (firstlogon){ firstlogon = atoi(row[15]); }
|
||||
}
|
||||
|
||||
|
||||
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
|
||||
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
|
||||
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
|
||||
database.LoadCharacterMaterialColor(cid, &m_pp); /* Load Character Material */
|
||||
database.LoadCharacterPotions(cid, &m_pp); /* Load Character Potion Belt */
|
||||
database.LoadCharacterCurrency(cid, &m_pp); /* Load Character Currency into PP */
|
||||
database.LoadCharacterData(cid, &m_pp); /* Load Character Data from DB into PP */
|
||||
database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); /* Move to another method when can, this is pointless... */
|
||||
database.LoadCharacterCurrency(cid, &m_pp); /* Load Character Currency */
|
||||
database.LoadCharacterSkills(cid, &m_pp); /* Load Character Skills */
|
||||
database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
|
||||
database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); /* Move to another method when can, this is pointless... */
|
||||
database.LoadCharacterSpellBook(cid, &m_pp); /* Load Character Spell Book */
|
||||
database.LoadCharacterMemmedSpells(cid, &m_pp); /* Load Character Memorized Spells */
|
||||
database.LoadCharacterDisciplines(cid, &m_pp); /* Load Character Disciplines */
|
||||
database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
|
||||
|
||||
if (level){ level = m_pp.level; }
|
||||
|
||||
@ -612,9 +609,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if (gmhideme) { trackable = false; }
|
||||
/* Set Con State for Reporting */
|
||||
conn_state = PlayerProfileLoaded;
|
||||
|
||||
// m_pp.zone_id = zone->GetZoneID();
|
||||
// m_pp.zoneInstance = zone->GetInstanceID();
|
||||
|
||||
/* Set Total Seconds Played */
|
||||
TotalSecondsPlayed = m_pp.timePlayedMin * 60;
|
||||
@ -9168,38 +9162,6 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) {
|
||||
Entity::DBAWComplete(workpt_b1, dbaw);
|
||||
switch (workpt_b1) {
|
||||
case DBA_b1_Entity_Client_Save: {
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
uint32 affected_rows = 0;
|
||||
DBAsyncQuery* dbaq = dbaw->PopAnswer();
|
||||
if (dbaq->GetAnswer(errbuf, 0, &affected_rows) && affected_rows == 1) {
|
||||
if (dbaq->QPT()) {
|
||||
SaveBackup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Async client save failed. '" << errbuf << "'" << std::endl;
|
||||
Message(13, "Error: Asyncronous save of your character failed.");
|
||||
if (Admin() >= 200)
|
||||
Message(13, "errbuf: %s", errbuf);
|
||||
}
|
||||
pQueuedSaveWorkID = 0;
|
||||
|
||||
LogFile->write(EQEMuLog::Status, "Client::DBAWComplete Save Character Async done... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
std::cout << "Error: Client::DBAWComplete(): Unknown workpt_b1" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish client connecting state */
|
||||
void Client::CompleteConnect() {
|
||||
UpdateWho();
|
||||
@ -9221,7 +9183,7 @@ void Client::CompleteConnect() {
|
||||
SendAppearancePacket(AT_GuildID, GuildID(), false);
|
||||
SendAppearancePacket(AT_GuildRank, GuildRank(), false);
|
||||
}
|
||||
for (uint32 spellInt = 0; spellInt < MAX_PP_SPELLBOOK; spellInt++) {
|
||||
for (uint32 spellInt = 0; spellInt < MAX_PP_REF_SPELLBOOK; spellInt++) {
|
||||
if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000)
|
||||
m_pp.spell_book[spellInt] = 0xFFFFFFFF;
|
||||
}
|
||||
@ -9417,7 +9379,7 @@ void Client::CompleteConnect() {
|
||||
SendWearChange(x);
|
||||
Mob *pet = GetPet();
|
||||
if (pet != nullptr) {
|
||||
for (x = 0; x < 8; x++)
|
||||
for (x = 0; x < 8; x++)
|
||||
pet->SendWearChange(x);
|
||||
}
|
||||
|
||||
@ -9497,6 +9459,8 @@ void Client::CompleteConnect() {
|
||||
alternate_currency_loaded = true;
|
||||
ProcessAlternateCurrencyQueue();
|
||||
|
||||
|
||||
|
||||
CalcItemScale();
|
||||
DoItemEnterZone();
|
||||
|
||||
@ -10504,8 +10468,7 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app) {
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) {
|
||||
|
||||
void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) {
|
||||
if(app->size != sizeof(MovePotionToBelt_Struct)) {
|
||||
LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_PotionBelt expected %i got %i",
|
||||
sizeof(MovePotionToBelt_Struct), app->size);
|
||||
@ -10519,6 +10482,7 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) {
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].item_id = BaseItem->ID;
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = BaseItem->Icon;
|
||||
strn0cpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, BaseItem->Name, sizeof(BaseItem->Name));
|
||||
database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.items[mptbs->SlotNumber].item_id, m_pp.potionbelt.items[mptbs->SlotNumber].icon);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -10526,9 +10490,6 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) {
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = 0;
|
||||
strncpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, "\0", 1);
|
||||
}
|
||||
|
||||
Save();
|
||||
|
||||
}
|
||||
|
||||
void Client::Handle_OP_LFGGetMatchesRequest(const EQApplicationPacket *app) {
|
||||
|
||||
@ -1717,6 +1717,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
uint16 skilllevel = GetRawSkill(skill);
|
||||
|
||||
if(skilllevel == 0) {
|
||||
//this is a new skill..
|
||||
uint16 t_level = SkillTrainLevel(skill, GetClass());
|
||||
@ -1726,7 +1727,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
SetSkill(skill, t_level);
|
||||
} else {
|
||||
} else {
|
||||
switch(skill) {
|
||||
case SkillBrewing:
|
||||
case SkillMakePoison:
|
||||
|
||||
@ -225,7 +225,6 @@ int command_init(void) {
|
||||
command_add("worldshutdown","- Shut down world and all zones",200,command_worldshutdown) ||
|
||||
command_add("sendzonespawns","- Refresh spawn list for all clients in zone",150,command_sendzonespawns) ||
|
||||
command_add("dbspawn2","[spawngroup] [respawn] [variance] - Spawn an NPC from a predefined row in the spawn2 table",100,command_dbspawn2) ||
|
||||
command_add("copychar","[character name] [new character] [new account id] - Create a copy of a character",100,command_copychar) ||
|
||||
command_add("shutdown","- Shut this zone process down",150,command_shutdown) ||
|
||||
command_add("delacct","[accountname] - Delete an account",150,command_delacct) ||
|
||||
command_add("setpass","[accountname] [password] - Set local password for accountname",150,command_setpass) ||
|
||||
@ -2227,28 +2226,6 @@ void command_dbspawn2(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void command_copychar(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(sep->arg[1][0]==0 || sep->arg[2][0] == 0 || sep->arg[3][0] == 0)
|
||||
c->Message(0, "Usage: #copychar [character name] [new character] [new account id]");
|
||||
//CheckUsedName.... TRUE=No Char, FALSE=Char/Error
|
||||
//If there is no source...
|
||||
else if (database.CheckUsedName((char*)sep->arg[1])) {
|
||||
c->Message(0, "Source character not found!");
|
||||
}
|
||||
else {
|
||||
//If there is a name is not used....
|
||||
if (database.CheckUsedName((char*) sep->arg[2])) {
|
||||
if (!database.CopyCharacter((char*) sep->arg[1], (char*) sep->arg[2], atoi(sep->arg[3])))
|
||||
c->Message(0, "Character copy operation failed!");
|
||||
else
|
||||
c->Message(0, "Character copy complete.");
|
||||
}
|
||||
else
|
||||
c->Message(0, "Target character already exists!");
|
||||
}
|
||||
}
|
||||
|
||||
void command_shutdown(Client *c, const Seperator *sep)
|
||||
{
|
||||
CatchSignal(2);
|
||||
@ -2423,8 +2400,8 @@ void command_showskills(Client *c, const Seperator *sep)
|
||||
|
||||
c->Message(0, "Skills for %s", t->GetName());
|
||||
for (SkillUseTypes i=Skill1HBlunt; i <= HIGHEST_SKILL; i=(SkillUseTypes)(i+1))
|
||||
c->Message(0, "Skill [%d] is at [%d]", i, t->GetSkill(i));
|
||||
}
|
||||
c->Message(0, "Skill [%d] is at [%d] - %u", i, t->GetSkill(i), t->GetRawSkill(i));
|
||||
}
|
||||
|
||||
void command_findspell(Client *c, const Seperator *sep)
|
||||
{
|
||||
@ -2801,7 +2778,7 @@ void command_charbackup(Client *c, const Seperator *sep)
|
||||
if (sep->IsNumber(2))
|
||||
charid = atoi(sep->arg[2]);
|
||||
else
|
||||
database.GetAccountIDByChar(sep->arg[2], &charid);
|
||||
database.GetAccountIDByChar(sep->arg[2]);
|
||||
if (charid) {
|
||||
if (database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"Select id, backupreason, charid, account_id, zoneid, DATE_FORMAT(ts, '%%m/%%d/%%Y %%H:%%i:%%s') "
|
||||
@ -2828,7 +2805,7 @@ void command_charbackup(Client *c, const Seperator *sep)
|
||||
if (sep->IsNumber(2))
|
||||
charid = atoi(sep->arg[2]);
|
||||
else
|
||||
database.GetAccountIDByChar(sep->arg[2], &charid);
|
||||
database.GetAccountIDByChar(sep->arg[2]);
|
||||
|
||||
if (charid && sep->IsNumber(3)) {
|
||||
uint32 cbid = atoi(sep->arg[3]);
|
||||
@ -8725,6 +8702,7 @@ void command_traindisc(Client *c, const Seperator *sep)
|
||||
break; //continue the 1st loop
|
||||
} else if(t->GetPP().disciplines.values[r] == 0) {
|
||||
t->GetPP().disciplines.values[r] = curspell;
|
||||
database.SaveCharacterDisc(c->CharacterID(), r, curspell);
|
||||
t->SendDisciplineUpdate();
|
||||
t->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
|
||||
@ -125,7 +125,6 @@ void command_worldshutdown(Client *c, const Seperator *sep);
|
||||
void command_sendzonespawns(Client *c, const Seperator *sep);
|
||||
void command_zsave(Client *c, const Seperator *sep);
|
||||
void command_dbspawn2(Client *c, const Seperator *sep);
|
||||
void command_copychar(Client *c, const Seperator *sep);
|
||||
void command_shutdown(Client *c, const Seperator *sep);
|
||||
void command_delacct(Client *c, const Seperator *sep);
|
||||
void command_setpass(Client *c, const Seperator *sep);
|
||||
|
||||
@ -606,6 +606,7 @@ bool Client::TrainDiscipline(uint32 itemid) {
|
||||
return(false);
|
||||
} else if(m_pp.disciplines.values[r] == 0) {
|
||||
m_pp.disciplines.values[r] = spell_id;
|
||||
database.SaveCharacterDisc(this->CharacterID(), r, spell_id);
|
||||
SendDisciplineUpdate();
|
||||
Message(0, "You have learned a new discipline!");
|
||||
return(true);
|
||||
|
||||
@ -40,7 +40,6 @@
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/features.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/dbasync.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "raids.h"
|
||||
#include "quest_parser_collection.h"
|
||||
@ -57,7 +56,6 @@ extern WorldServer worldserver;
|
||||
extern NetConnection net;
|
||||
extern uint32 numclients;
|
||||
extern PetitionList petition_list;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
extern char errorname[32];
|
||||
extern uint16 adverrornum;
|
||||
@ -65,12 +63,11 @@ extern uint16 adverrornum;
|
||||
Entity::Entity()
|
||||
{
|
||||
id = 0;
|
||||
pDBAsyncWorkID = 0;
|
||||
}
|
||||
|
||||
Entity::~Entity()
|
||||
{
|
||||
dbasync->CancelWork(pDBAsyncWorkID);
|
||||
|
||||
}
|
||||
|
||||
Client *Entity::CastToClient()
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
|
||||
#include "zonedb.h"
|
||||
#include "zonedump.h"
|
||||
#include "zonedbasync.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
class EQApplicationPacket;
|
||||
@ -53,7 +52,7 @@ class Bot;
|
||||
class BotRaids;
|
||||
#endif
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern EntityList entity_list;
|
||||
|
||||
class Entity
|
||||
{
|
||||
@ -100,7 +99,6 @@ public:
|
||||
inline const uint16& GetID() const { return id; }
|
||||
|
||||
virtual const char* GetName() { return ""; }
|
||||
virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { pDBAsyncWorkID = 0; }
|
||||
bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1);
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
@ -51,14 +51,7 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
uint32 add_exp = in_add_exp;
|
||||
|
||||
|
||||
@ -200,14 +200,7 @@ bool Client::CheckLoreConflict(const Item_Struct* item) {
|
||||
}
|
||||
|
||||
bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, uint16 to_slot) {
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Recieved_Item", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
// TODO: update calling methods and script apis to handle a failure return
|
||||
|
||||
@ -2320,10 +2313,8 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
|
||||
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
|
||||
|
||||
const ItemInst* InvItem;
|
||||
|
||||
const Item_Struct *BaseItem;
|
||||
|
||||
const ItemInst* InvItem;
|
||||
const Item_Struct *BaseItem;
|
||||
int16 WeaponSlot;
|
||||
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
@ -2334,6 +2325,7 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot);
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = BaseItem->ID;
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = BaseItem->Icon;
|
||||
database.SaveCharacterBandolier(this->CharacterID(), bs->number, BandolierSlot, m_pp.bandoliers[bs->number].items[BandolierSlot].item_id, m_pp.bandoliers[bs->number].items[BandolierSlot].icon, bs->name);
|
||||
}
|
||||
else {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s no item in slot %i", GetName(), WeaponSlot);
|
||||
@ -2341,21 +2333,17 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = 0;
|
||||
}
|
||||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
void Client::RemoveBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
// Delete bandolier with the specified number
|
||||
|
||||
BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer;
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s removing set", GetName(), bds->number);
|
||||
memset(m_pp.bandoliers[bds->number].name, 0, 32);
|
||||
for(int i = bandolierMainHand; i <= bandolierAmmo; i++) {
|
||||
m_pp.bandoliers[bds->number].items[i].item_id = 0;
|
||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
||||
}
|
||||
Save();
|
||||
database.DeleteCharacterBandolier(this->CharacterID(), bds->number);
|
||||
}
|
||||
|
||||
void Client::SetBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
10
zone/net.cpp
10
zone/net.cpp
@ -97,8 +97,6 @@ extern Zone* zone;
|
||||
EQStreamFactory eqsf(ZoneStream);
|
||||
npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
TitleManager title_manager;
|
||||
DBAsyncFinishedQueue MTdbafq;
|
||||
DBAsync *dbasync = nullptr;
|
||||
QueryServ *QServ = 0;
|
||||
TaskManager *taskmanager = 0;
|
||||
QuestParserCollection *parse = 0;
|
||||
@ -168,8 +166,6 @@ int main(int argc, char** argv) {
|
||||
_log(ZONE__INIT_ERR, "Cannot continue without a database connection.");
|
||||
return 1;
|
||||
}
|
||||
dbasync = new DBAsync(&database);
|
||||
dbasync->AddFQ(&MTdbafq);
|
||||
guild_mgr.SetDatabase(&database);
|
||||
|
||||
GuildBanks = nullptr;
|
||||
@ -444,10 +440,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
}
|
||||
}
|
||||
DBAsyncWork* dbaw = 0;
|
||||
while ((dbaw = MTdbafq.Pop())) {
|
||||
DispatchFinishedDBAsync(dbaw);
|
||||
}
|
||||
if (InterserverTimer.Check()) {
|
||||
InterserverTimer.Start();
|
||||
database.ping();
|
||||
@ -507,8 +499,6 @@ int main(int argc, char** argv) {
|
||||
//Fix for Linux world server problem.
|
||||
eqsf.Close();
|
||||
worldserver.Disconnect();
|
||||
dbasync->CommitWrites();
|
||||
dbasync->StopThread();
|
||||
safe_delete(taskmanager);
|
||||
command_deinit();
|
||||
safe_delete(parse);
|
||||
|
||||
@ -974,6 +974,7 @@ uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||
SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID);
|
||||
if (SpellGlobalCheckResult) {
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
database.SaveCharacterDisc(Char_ID, r, curspell);
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
@ -981,11 +982,12 @@ uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||
break; //continue the 1st loop
|
||||
}
|
||||
else {
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
break; //continue the 1st loop
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
database.SaveCharacterDisc(Char_ID, r, curspell);
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
break; //continue the 1st loop
|
||||
}
|
||||
} //if we get to this point, there's already a discipline in this slot, so we skip it
|
||||
}
|
||||
|
||||
@ -4933,8 +4933,9 @@ void Client::UntrainDisc(int slot, bool update_client)
|
||||
if(slot >= MAX_PP_DISCIPLINES || slot < 0)
|
||||
return;
|
||||
|
||||
mlog(CLIENT__SPELLS, "Discipline %d untrained from slot %d", m_pp.disciplines.values[slot], slot);
|
||||
mlog(CLIENT__SPELLS, "Discipline %d untrained from slot %d", m_pp.disciplines.values[slot], slot);
|
||||
m_pp.disciplines.values[slot] = 0;
|
||||
database.DeleteCharacterDisc(this->CharacterID(), slot);
|
||||
|
||||
if(update_client)
|
||||
{
|
||||
|
||||
@ -913,14 +913,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
if(!tradingWith->IsMoving())
|
||||
tradingWith->FaceTarget(this);
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
}
|
||||
}
|
||||
@ -938,7 +931,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
parse->AddVar(temp1, temp2);
|
||||
snprintf(temp1, 100, "platinum.%d", tradingWith->GetNPCTypeID());
|
||||
snprintf(temp2, 100, "%u", trade->pp);
|
||||
parse->AddVar(temp1, temp2);
|
||||
parse->AddVar(temp1, temp2);
|
||||
|
||||
if(tradingWith->GetAppearance() != eaDead) {
|
||||
tradingWith->FaceTarget(this);
|
||||
|
||||
@ -254,8 +254,10 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
//make sure they have enough of them
|
||||
//and remove it from inventory
|
||||
/*
|
||||
Make sure they have enough of them
|
||||
and remove it from inventory
|
||||
*/
|
||||
if(inst->IsStackable()) {
|
||||
if(inst->GetCharges() < (int32)quantity) //dont have enough....
|
||||
return(0);
|
||||
@ -267,7 +269,7 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) {
|
||||
|
||||
pts *= quantity;
|
||||
|
||||
//add the tribute value in points
|
||||
/* Add the tribute value in points */
|
||||
AddTributePoints(pts);
|
||||
return(pts);
|
||||
}
|
||||
@ -279,7 +281,7 @@ int32 Client::TributeMoney(uint32 platinum) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
//add the tribute value in points
|
||||
/* Add the tribute value in points */
|
||||
AddTributePoints(platinum);
|
||||
return(platinum);
|
||||
}
|
||||
|
||||
@ -77,8 +77,6 @@ extern bool staticzone;
|
||||
Zone* zone = 0;
|
||||
volatile bool ZoneLoaded = false;
|
||||
extern QuestParserCollection* parse;
|
||||
extern DBAsyncFinishedQueue MTdbafq;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
|
||||
const char* zonename = database.GetZoneName(iZoneID);
|
||||
@ -705,7 +703,6 @@ void Zone::Shutdown(bool quite)
|
||||
|
||||
zone->ResetAuth();
|
||||
safe_delete(zone);
|
||||
dbasync->CommitWrites();
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests(true);
|
||||
UpdateWindowTitle();
|
||||
@ -844,8 +841,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
}
|
||||
|
||||
Zone::~Zone() {
|
||||
if(pQueuedMerchantsWorkID != 0)
|
||||
dbasync->CancelWork(pQueuedMerchantsWorkID);
|
||||
spawn2_list.Clear();
|
||||
safe_delete(zonemap);
|
||||
safe_delete(watermap);
|
||||
|
||||
395
zone/zonedb.cpp
395
zone/zonedb.cpp
@ -626,8 +626,7 @@ TraderCharges_Struct* ZoneDatabase::LoadTraderItemWithCharges(uint32 char_id){
|
||||
return loadti;
|
||||
}
|
||||
|
||||
ItemInst* ZoneDatabase::LoadSingleTraderItem(uint32 CharID, int SerialNumber) {
|
||||
|
||||
ItemInst* ZoneDatabase::LoadSingleTraderItem(uint32 CharID, int SerialNumber) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
@ -687,8 +686,7 @@ void ZoneDatabase::SaveTraderItem(uint32 CharID, uint32 ItemID, uint32 SerialNum
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::UpdateTraderItemCharges(int CharID, uint32 SerialNumber, int32 Charges) {
|
||||
|
||||
void ZoneDatabase::UpdateTraderItemCharges(int CharID, uint32 SerialNumber, int32 Charges) {
|
||||
_log(TRADING__CLIENT, "ZoneDatabase::UpdateTraderItemCharges(%i, %i, %i)", CharID, SerialNumber, Charges);
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
@ -784,8 +782,7 @@ void ZoneDatabase::DeleteBuyLines(uint32 CharID){
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char* ItemName, uint32 Quantity, uint32 Price) {
|
||||
|
||||
void ZoneDatabase::AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char* ItemName, uint32 Quantity, uint32 Price) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
if (!(RunQuery(query,MakeAnyLenString(&query, "replace INTO buyer VALUES(%i,%i, %i,\"%s\",%i,%i)",
|
||||
@ -795,8 +792,7 @@ void ZoneDatabase::AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, cons
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::RemoveBuyLine(uint32 CharID, uint32 BuySlot) {
|
||||
|
||||
void ZoneDatabase::RemoveBuyLine(uint32 CharID, uint32 BuySlot) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
@ -806,8 +802,7 @@ void ZoneDatabase::RemoveBuyLine(uint32 CharID, uint32 BuySlot) {
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity) {
|
||||
|
||||
void ZoneDatabase::UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity) {
|
||||
if(Quantity <= 0) {
|
||||
RemoveBuyLine(CharID, BuySlot);
|
||||
return;
|
||||
@ -1016,7 +1011,7 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct*
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterFactionValues(uint32 character_id, faction_map & val_list) {
|
||||
std::string query = StringFormat("SELECT faction_id,current_value FROM faction_values WHERE char_id = %i", character_id);
|
||||
std::string query = StringFormat("SELECT `faction_id`, `current_value` FROM `faction_values` WHERE `char_id` = %i", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { val_list[atoi(row[0])] = atoi(row[1]); }
|
||||
return true;
|
||||
@ -1055,8 +1050,12 @@ bool ZoneDatabase::LoadCharacterLanguages(uint32 character_id, PlayerProfile_Str
|
||||
"`value` "
|
||||
"FROM "
|
||||
"`character_languages` "
|
||||
"WHERE `id` = %u ORDER BY `language_id`", character_id);
|
||||
"WHERE `id` = %u ORDER BY `lang_id`", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
/* Initialize Languages */
|
||||
for (i = 0; i < MAX_PP_LANGUAGE; i++){
|
||||
pp->languages[i] = 0;
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->languages[i] = atoi(row[1]); }
|
||||
return true;
|
||||
}
|
||||
@ -1069,8 +1068,8 @@ bool ZoneDatabase::LoadCharacterDisciplines(uint32 character_id, PlayerProfile_S
|
||||
"`character_disciplines`"
|
||||
"WHERE `id` = %u ORDER BY `disc_id`", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { pp->disciplines.values[i] = atoi(row[0]); i++; }
|
||||
return true;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { pp->disciplines.values[i] = atoi(row[0]); i++; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
@ -1081,7 +1080,11 @@ bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct
|
||||
"FROM "
|
||||
"`character_skills` "
|
||||
"WHERE `id` = %u ORDER BY `skill_id`", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
/* Initialize Skill */
|
||||
for (i = 0; i < MAX_PP_SKILL; i++){
|
||||
pp->skills[i] = 0;
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->skills[i] = atoi(row[1]); }
|
||||
return true;
|
||||
}
|
||||
@ -1131,44 +1134,162 @@ bool ZoneDatabase::LoadCharacterCurrency(uint32 character_id, PlayerProfile_Stru
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT slot, blue, green, red, use_tint, color FROM `character_material` WHERE `id` = %u LIMIT 9", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
i = atoi(row[r]); /* Slot */ r++;
|
||||
pp->item_tint[i].rgb.blue = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.green = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.red = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.use_tint = atoi(row[r]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0;
|
||||
for (i = 0; i <= EmuConstants::BANDOLIERS_COUNT; i++){
|
||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){
|
||||
pp->bandoliers[i].items[si].icon = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
i = atoi(row[r]); /* Bandolier ID */ r++;
|
||||
si = atoi(row[r]); /* Bandolier Slot */ r++;
|
||||
pp->bandoliers[i].items[si].item_id = atoi(row[r]); r++;
|
||||
pp->bandoliers[i].items[si].icon = atoi(row[r]); r++;
|
||||
strcpy(pp->bandoliers[i].name, row[r]); r++;
|
||||
si++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `tier`, `tribute` FROM `character_tribute` WHERE `id` = %u", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
for (i = 0; i < EmuConstants::TRIBUTE_SIZE; i++){
|
||||
pp->tributes[i].tribute = 0;
|
||||
pp->tributes[i].tier = 0;
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
pp->tributes[i].tier = atoi(row[0]);
|
||||
pp->tributes[i].tribute = atoi(row[1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){
|
||||
pp->potionbelt.items[i].icon = 0;
|
||||
pp->potionbelt.items[i].item_id = 0;
|
||||
strncpy(pp->potionbelt.items[i].item_name, "\0", 1);
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]); /* Potion belt slot number */
|
||||
pp->potionbelt.items[i].item_id = atoi(row[1]);
|
||||
pp->potionbelt.items[i].icon = atoi(row[2]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT id, zone_id, instance_id, x, y, z, heading FROM character_bind_home WHERE `id` = %u", character_id);
|
||||
std::string query = StringFormat("SELECT zone_id, instance_id, x, y, z, heading, is_home FROM character_bind WHERE `id` = %u LIMIT 2", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
pp->binds[4].zoneId = atoi(row[i]); i++;
|
||||
i++; /* Instance ID can go here eventually */
|
||||
pp->binds[4].x = atoi(row[i]); i++;
|
||||
pp->binds[4].y = atoi(row[i]); i++;
|
||||
pp->binds[4].z = atoi(row[i]); i++;
|
||||
pp->binds[4].heading = atoi(row[i]); i++;
|
||||
i = 0;
|
||||
/* Is home bind */
|
||||
if (atoi(row[6]) == 1){
|
||||
pp->binds[4].zoneId = atoi(row[i]); i++;
|
||||
i++; /* Instance ID can go here eventually */
|
||||
pp->binds[4].x = atoi(row[i]); i++;
|
||||
pp->binds[4].y = atoi(row[i]); i++;
|
||||
pp->binds[4].z = atoi(row[i]); i++;
|
||||
pp->binds[4].heading = atoi(row[i]); i++;
|
||||
}
|
||||
/* Is regular bind point */
|
||||
else{
|
||||
pp->binds[0].zoneId = atoi(row[i]); i++;
|
||||
i++; /* Instance ID can go here eventually */
|
||||
pp->binds[0].x = atoi(row[i]); i++;
|
||||
pp->binds[0].y = atoi(row[i]); i++;
|
||||
pp->binds[0].z = atoi(row[i]); i++;
|
||||
pp->binds[0].heading = atoi(row[i]); i++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value){
|
||||
std::string query = StringFormat("REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)", character_id, lang_id, value); QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterLanguage for character ID: %i, lang_id:%u value:%u done", character_id, lang_id, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home){
|
||||
/* Save Home Bind Point */
|
||||
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, zone_id, instance_id, x, y, z, heading, is_home);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterBindPoint for character ID: %i zone_id: %u instance_id: %u x: %f y: %f z: %f heading: %f ishome: %u", character_id, zone_id, instance_id, x, y, z, heading, is_home);
|
||||
auto results = QueryDatabase(query); if (!results.RowsAffected()){ std::cout << "ERROR Bind Home Save: " << results.ErrorMessage() << "\n\n" << query << "\n" << std::endl; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color){
|
||||
std::string query = StringFormat("REPLACE INTO `character_material` (id, slot, color, use_tint) VALUES (%u, %u, %u, 255)", character_id, slot_id, color); QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterMaterialColor for character ID: %i, slot_id: %u color: %u done", character_id, slot_id, color);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT slot, blue, green, red, use_tint, color FROM `character_material` WHERE `id` = %u LIMIT 9", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
i = atoi(row[r]); /* Slot */ r++;
|
||||
pp->item_tint[i].rgb.blue = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.green = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.red = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.use_tint = atoi(row[r]);
|
||||
printf("Material Load: %u %u %u %u\n", pp->item_tint[i].rgb.blue, pp->item_tint[i].rgb.green, pp->item_tint[i].rgb.red, pp->item_tint[i].rgb.use_tint);
|
||||
bool ZoneDatabase::SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value){
|
||||
std::string query = StringFormat("REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)", character_id, skill_id, value); QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterSkill for character ID: %i, skill_id:%u value:%u done", character_id, skill_id, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id){
|
||||
std::string query = StringFormat("REPLACE INTO `character_disciplines` (id, slot_id, disc_id) VALUES (%u, %u, %u)", character_id, slot_id, disc_id); QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterDisc for character ID: %i, slot:%u disc_id:%u value:%u done", character_id, slot_id, disc_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query);
|
||||
/* Save Tributes only if we have values... */
|
||||
for (int i = 0; i < EmuConstants::TRIBUTE_SIZE; i++){
|
||||
if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != UINT32_MAX){
|
||||
std::string query = StringFormat("REPLACE INTO `character_tribute` (id, tier, tribute) VALUES (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute); QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterTribute for character ID: %i, tier:%u tribute:%u done", character_id, pp->tributes[i].tier, pp->tributes[i].tribute);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name){
|
||||
char bandolier_name_esc[64];
|
||||
DoEscapeString(bandolier_name_esc, bandolier_name, strlen(bandolier_name));
|
||||
std::string query = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%u, %u, %u, %u, %u,'%s')", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name_esc);
|
||||
auto results = QueryDatabase(query);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterBandolier for character ID: %i, bandolier_id: %u, bandolier_slot: %u item_id: %u, icon:%u band_name:%s done", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name);
|
||||
if (!results.RowsAffected()){ std::cout << "ERROR Bandolier Save: " << results.ErrorMessage() << "\n\n" << query << "\n" << std::endl; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon) {
|
||||
std::string query = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%u, %u, %u, %u)", character_id, potion_id, item_id, icon);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.RowsAffected()){ std::cout << "ERROR Potionbelt Save: " << results.ErrorMessage() << "\n\n" << query << "\n" << std::endl; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp){
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
if (pp->tribute_time_remaining < 0 || pp->tribute_time_remaining == 4294967295){ pp->tribute_time_remaining = 0; }
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_data` ("
|
||||
" id, "
|
||||
@ -1352,97 +1473,97 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
"%u," // raid_auto_consent pp->raidAutoconsent, " raid_auto_consent, "
|
||||
"%u," // guild_auto_consent pp->guildAutoconsent, " guild_auto_consent, "
|
||||
"%u" // RestTimer pp->RestTimer, " RestTimer) "
|
||||
")",
|
||||
character_id,
|
||||
account_id,
|
||||
pp->name,
|
||||
pp->last_name,
|
||||
pp->gender,
|
||||
pp->race,
|
||||
pp->class_,
|
||||
pp->level,
|
||||
pp->deity,
|
||||
pp->birthday,
|
||||
pp->lastlogin,
|
||||
pp->timePlayedMin,
|
||||
pp->pvp,
|
||||
pp->level2,
|
||||
pp->anon,
|
||||
pp->gm,
|
||||
pp->intoxication,
|
||||
pp->haircolor,
|
||||
pp->beardcolor,
|
||||
pp->eyecolor1,
|
||||
pp->eyecolor2,
|
||||
pp->hairstyle,
|
||||
pp->beard,
|
||||
pp->ability_time_seconds,
|
||||
pp->ability_number,
|
||||
pp->ability_time_minutes,
|
||||
pp->ability_time_hours,
|
||||
pp->title,
|
||||
pp->suffix,
|
||||
pp->exp,
|
||||
pp->points,
|
||||
pp->mana,
|
||||
pp->cur_hp,
|
||||
pp->STR,
|
||||
pp->STA,
|
||||
pp->CHA,
|
||||
pp->DEX,
|
||||
pp->INT,
|
||||
pp->AGI,
|
||||
pp->WIS,
|
||||
pp->face,
|
||||
pp->y,
|
||||
pp->x,
|
||||
pp->z,
|
||||
pp->heading,
|
||||
pp->pvp2,
|
||||
pp->pvptype,
|
||||
pp->autosplit,
|
||||
pp->zone_change_count,
|
||||
pp->drakkin_heritage,
|
||||
pp->drakkin_tattoo,
|
||||
pp->drakkin_details,
|
||||
pp->toxicity,
|
||||
pp->hunger_level,
|
||||
pp->thirst_level,
|
||||
pp->ability_up,
|
||||
pp->zone_id,
|
||||
pp->zoneInstance,
|
||||
pp->leadAAActive,
|
||||
pp->ldon_points_guk,
|
||||
pp->ldon_points_mir,
|
||||
pp->ldon_points_mmc,
|
||||
pp->ldon_points_ruj,
|
||||
pp->ldon_points_tak,
|
||||
pp->ldon_points_available,
|
||||
pp->tribute_time_remaining,
|
||||
pp->showhelm,
|
||||
pp->career_tribute_points,
|
||||
pp->tribute_points,
|
||||
pp->tribute_active,
|
||||
pp->endurance,
|
||||
pp->group_leadership_exp,
|
||||
pp->raid_leadership_exp,
|
||||
pp->group_leadership_points,
|
||||
pp->raid_leadership_points,
|
||||
pp->air_remaining,
|
||||
pp->PVPKills,
|
||||
pp->PVPDeaths,
|
||||
pp->PVPCurrentPoints,
|
||||
pp->PVPCareerPoints,
|
||||
pp->PVPBestKillStreak,
|
||||
pp->PVPWorstDeathStreak,
|
||||
pp->PVPCurrentKillStreak,
|
||||
pp->aapoints_spent,
|
||||
pp->expAA,
|
||||
pp->aapoints,
|
||||
pp->groupAutoconsent,
|
||||
pp->raidAutoconsent,
|
||||
pp->guildAutoconsent,
|
||||
pp->RestTimer
|
||||
")",
|
||||
character_id, // " id, "
|
||||
account_id, // " account_id, "
|
||||
pp->name, // " `name`, "
|
||||
pp->last_name, // " last_name, "
|
||||
pp->gender, // " gender, "
|
||||
pp->race, // " race, "
|
||||
pp->class_, // " class, "
|
||||
pp->level, // " `level`, "
|
||||
pp->deity, // " deity, "
|
||||
pp->birthday, // " birthday, "
|
||||
pp->lastlogin, // " last_login, "
|
||||
pp->timePlayedMin, // " time_played, "
|
||||
pp->pvp, // " pvp_status, "
|
||||
pp->level2, // " level2, "
|
||||
pp->anon, // " anon, "
|
||||
pp->gm, // " gm, "
|
||||
pp->intoxication, // " intoxication, "
|
||||
pp->haircolor, // " hair_color, "
|
||||
pp->beardcolor, // " beard_color, "
|
||||
pp->eyecolor1, // " eye_color_1, "
|
||||
pp->eyecolor2, // " eye_color_2, "
|
||||
pp->hairstyle, // " hair_style, "
|
||||
pp->beard, // " beard, "
|
||||
pp->ability_time_seconds, // " ability_time_seconds, "
|
||||
pp->ability_number, // " ability_number, "
|
||||
pp->ability_time_minutes, // " ability_time_minutes, "
|
||||
pp->ability_time_hours, // " ability_time_hours, "
|
||||
pp->title, // " title, "
|
||||
pp->suffix, // " suffix, "
|
||||
pp->exp, // " exp, "
|
||||
pp->points, // " points, "
|
||||
pp->mana, // " mana, "
|
||||
pp->cur_hp, // " cur_hp, "
|
||||
pp->STR, // " str, "
|
||||
pp->STA, // " sta, "
|
||||
pp->CHA, // " cha, "
|
||||
pp->DEX, // " dex, "
|
||||
pp->INT, // " `int`, "
|
||||
pp->AGI, // " agi, "
|
||||
pp->WIS, // " wis, "
|
||||
pp->face, // " face, "
|
||||
pp->y, // " y, "
|
||||
pp->x, // " x, "
|
||||
pp->z, // " z, "
|
||||
pp->heading, // " heading, "
|
||||
pp->pvp2, // " pvp2, "
|
||||
pp->pvptype, // " pvp_type, "
|
||||
pp->autosplit, // " autosplit_enabled, "
|
||||
pp->zone_change_count, // " zone_change_count, "
|
||||
pp->drakkin_heritage, // " drakkin_heritage, "
|
||||
pp->drakkin_tattoo, // " drakkin_tattoo, "
|
||||
pp->drakkin_details, // " drakkin_details, "
|
||||
pp->toxicity, // " toxicity, "
|
||||
pp->hunger_level, // " hunger_level, "
|
||||
pp->thirst_level, // " thirst_level, "
|
||||
pp->ability_up, // " ability_up, "
|
||||
pp->zone_id, // " zone_id, "
|
||||
pp->zoneInstance, // " zone_instance, "
|
||||
pp->leadAAActive, // " leadership_exp_on, "
|
||||
pp->ldon_points_guk, // " ldon_points_guk, "
|
||||
pp->ldon_points_mir, // " ldon_points_mir, "
|
||||
pp->ldon_points_mmc, // " ldon_points_mmc, "
|
||||
pp->ldon_points_ruj, // " ldon_points_ruj, "
|
||||
pp->ldon_points_tak, // " ldon_points_tak, "
|
||||
pp->ldon_points_available, // " ldon_points_available, "
|
||||
pp->tribute_time_remaining, // " tribute_time_remaining, "
|
||||
pp->showhelm, // " show_helm, "
|
||||
pp->career_tribute_points, // " career_tribute_points, "
|
||||
pp->tribute_points, // " tribute_points, "
|
||||
pp->tribute_active, // " tribute_active, "
|
||||
pp->endurance, // " endurance, "
|
||||
pp->group_leadership_exp, // " group_leadership_exp, "
|
||||
pp->raid_leadership_exp, // " raid_leadership_exp, "
|
||||
pp->group_leadership_points, // " group_leadership_points, "
|
||||
pp->raid_leadership_points, // " raid_leadership_points, "
|
||||
pp->air_remaining, // " air_remaining, "
|
||||
pp->PVPKills, // " pvp_kills, "
|
||||
pp->PVPDeaths, // " pvp_deaths, "
|
||||
pp->PVPCurrentPoints, // " pvp_current_points, "
|
||||
pp->PVPCareerPoints, // " pvp_career_points, "
|
||||
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
|
||||
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
|
||||
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
|
||||
pp->aapoints_spent, // " aa_points_spent, "
|
||||
pp->expAA, // " aa_exp, "
|
||||
pp->aapoints, // " aa_points, "
|
||||
pp->groupAutoconsent, // " group_auto_consent, "
|
||||
pp->raidAutoconsent, // " raid_auto_consent, "
|
||||
pp->guildAutoconsent, // " guild_auto_consent, "
|
||||
pp->RestTimer // " RestTimer) "
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.RowsAffected()){ std::cout << "ERROR ZoneDatabase:SaveCharacterData: " << results.ErrorMessage() << "\n\n" << query << "\n" << std::endl; }
|
||||
@ -1459,6 +1580,10 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru
|
||||
if (pp->silver_bank < 0) { pp->silver_bank = 0; }
|
||||
if (pp->gold_bank < 0) { pp->gold_bank = 0; }
|
||||
if (pp->platinum_bank < 0) { pp->platinum_bank = 0; }
|
||||
if (pp->platinum_cursor < 0) { pp->platinum_cursor = 0; }
|
||||
if (pp->gold_cursor < 0) { pp->gold_cursor = 0; }
|
||||
if (pp->silver_cursor < 0) { pp->silver_cursor = 0; }
|
||||
if (pp->copper_cursor < 0) { pp->copper_cursor = 0; }
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_currency` (id, platinum, gold, silver, copper,"
|
||||
"platinum_bank, gold_bank, silver_bank, copper_bank,"
|
||||
@ -1499,12 +1624,16 @@ bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 cur
|
||||
bool ZoneDatabase::SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot){
|
||||
std::string rquery = StringFormat("UPDATE `character_spells` SET `slot_id` = %u WHERE `slot_id` = %u AND `id` = %u",
|
||||
to_slot, from_slot, character_id);
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
auto results = QueryDatabase(rquery);
|
||||
LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterSpellSwap for character ID: %u, from_slot: %u to_slot: %u spell: %u time: %f seconds", character_id, from_slot, to_slot, spell_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){
|
||||
std::string query = StringFormat("REPLACE INTO `character_memmed_spells` (id, slot_id, spell_id) VALUES (%u, %u, %u)", character_id, slot_id, spell_id); QueryDatabase(query); return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){
|
||||
std::string query = StringFormat("REPLACE INTO `character_spells` (id, slot_id, spell_id) VALUES (%u, %u, %u)", character_id, slot_id, spell_id); QueryDatabase(query); return true;
|
||||
}
|
||||
@ -1513,8 +1642,12 @@ bool ZoneDatabase::DeleteCharacterSpell(uint32 character_id, uint32 spell_id, ui
|
||||
std::string query = StringFormat("DELETE FROM `character_spells` WHERE `slot_id` = %u AND `id` = %u", slot_id, character_id); QueryDatabase(query); return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){
|
||||
std::string query = StringFormat("REPLACE INTO `character_memmed_spells` (id, slot_id, spell_id) VALUES (%u, %u, %u)", character_id, slot_id, spell_id); QueryDatabase(query); return true;
|
||||
bool ZoneDatabase::DeleteCharacterDisc(uint32 character_id, uint32 slot_id){
|
||||
std::string query = StringFormat("DELETE FROM `character_disciplines` WHERE `slot_id` = %u AND `id` = %u", slot_id, character_id); QueryDatabase(query); return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::DeleteCharacterBandolier(uint32 character_id, uint32 band_id){
|
||||
std::string query = StringFormat("DELETE FROM `character_bandolier` WHERE `bandolier_id` = %u AND `id` = %u", band_id, character_id); QueryDatabase(query); return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){
|
||||
@ -1715,7 +1848,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
tmpNPCType->aggroradius = (int32)atoi(row[r++]);
|
||||
// set defaultvalue for aggroradius
|
||||
if (tmpNPCType->aggroradius <= 0)
|
||||
tmpNPCType->aggroradius = 70;
|
||||
tmpNPCType->aggroradius = 70;
|
||||
tmpNPCType->assistradius = (int32)atoi(row[r++]);
|
||||
if (tmpNPCType->assistradius <= 0)
|
||||
tmpNPCType->assistradius = tmpNPCType->aggroradius;
|
||||
@ -3715,4 +3848,6 @@ void ZoneDatabase::StoreCharacterLookup(uint32 char_id) {
|
||||
" FROM `character_` "
|
||||
" WHERE `id` = %i ", char_id);
|
||||
QueryDatabase(c_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
148
zone/zonedb.h
148
zone/zonedb.h
@ -6,6 +6,7 @@
|
||||
#include "../common/loottable.h"
|
||||
#include "zonedump.h"
|
||||
#include "../common/faction.h"
|
||||
#include <stdint.h>
|
||||
//#include "doors.h"
|
||||
|
||||
struct wplist {
|
||||
@ -212,9 +213,7 @@ public:
|
||||
ZoneDatabase(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
virtual ~ZoneDatabase();
|
||||
|
||||
/*
|
||||
* Objects and World Containers
|
||||
*/
|
||||
/* Objects and World Containers */
|
||||
void LoadWorldContainer(uint32 parentid, ItemInst* container);
|
||||
void SaveWorldContainer(uint32 zone_id, uint32 parent_id, const ItemInst* container);
|
||||
void DeleteWorldContainer(uint32 parent_id,uint32 zone_id);
|
||||
@ -223,10 +222,7 @@ public:
|
||||
void DeleteObject(uint32 id);
|
||||
Ground_Spawns* LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs);
|
||||
|
||||
/*
|
||||
* Traders
|
||||
*/
|
||||
|
||||
/* Traders */
|
||||
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
||||
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
||||
void UpdateTraderItemPrice(int CharID, uint32 ItemID, uint32 Charges, uint32 NewPrice);
|
||||
@ -236,16 +232,13 @@ public:
|
||||
Trader_Struct* LoadTraderItem(uint32 char_id);
|
||||
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
||||
|
||||
// Buyer/Barter
|
||||
//
|
||||
/* Buyer/Barter */
|
||||
void AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char *ItemName, uint32 Quantity, uint32 Price);
|
||||
void RemoveBuyLine(uint32 CharID, uint32 BuySlot);
|
||||
void DeleteBuyLines(uint32 CharID);
|
||||
void UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity);
|
||||
|
||||
/*
|
||||
* General Character Related Stuff
|
||||
*/
|
||||
/* General Character Related Stuff */
|
||||
void StoreCharacterLookup(uint32 char_id);
|
||||
bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
|
||||
uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
|
||||
@ -267,28 +260,36 @@ public:
|
||||
bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
|
||||
/* Character Data Saves */
|
||||
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
|
||||
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
|
||||
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
|
||||
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
|
||||
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
|
||||
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
|
||||
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
|
||||
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
|
||||
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
|
||||
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
|
||||
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
|
||||
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
|
||||
|
||||
/* Character Data Deletes */
|
||||
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
|
||||
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
|
||||
|
||||
/*
|
||||
* Character Inventory
|
||||
*/
|
||||
/* Character Inventory */
|
||||
bool NoRentExpired(const char* name);
|
||||
|
||||
/*
|
||||
* Corpses
|
||||
*/
|
||||
/* Corpses */
|
||||
bool GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes);
|
||||
uint32 CreatePlayerCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading);
|
||||
bool CreatePlayerCorpseBackup(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading);
|
||||
@ -314,9 +315,7 @@ public:
|
||||
uint32 GetPlayerCorpseItemAt(uint32 corpse_id, uint16 slotid);
|
||||
uint32 GetPlayerCorpseTimeLeft(uint8 corpse, uint8 type);
|
||||
|
||||
/*
|
||||
* Faction
|
||||
*/
|
||||
/* Faction */
|
||||
bool GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, int32* value, uint8* temp, int32* primary_faction = 0);
|
||||
bool GetFactionData(FactionMods* fd, uint32 class_mod, uint32 race_mod, uint32 deity_mod, int32 faction_id); //rembrant, needed for factions Dec, 16 2001
|
||||
bool GetFactionName(int32 faction_id, char* name, uint32 buflen); // rembrant, needed for factions Dec, 16 2001
|
||||
@ -324,9 +323,7 @@ public:
|
||||
bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // rembrant, needed for factions Dec, 16 2001
|
||||
bool LoadFactionData();
|
||||
|
||||
/*
|
||||
* AAs
|
||||
*/
|
||||
/* AAs */
|
||||
bool LoadAAEffects();
|
||||
bool LoadAAEffects2();
|
||||
bool LoadSwarmSpells();
|
||||
@ -338,9 +335,7 @@ public:
|
||||
uint32 CountAAEffects();
|
||||
void FillAAEffects(SendAA_Struct* aa_struct);
|
||||
|
||||
/*
|
||||
* Zone related
|
||||
*/
|
||||
/* Zone related */
|
||||
bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename);
|
||||
bool SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct* zd);
|
||||
bool LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list,const char* zonename, uint32 version);
|
||||
@ -348,9 +343,7 @@ public:
|
||||
uint8 GetUseCFGSafeCoords();
|
||||
int getZoneShutDownDelay(uint32 zoneID, uint32 version);
|
||||
|
||||
/*
|
||||
* Spawns and Spawn Points
|
||||
*/
|
||||
/* Spawns and Spawn Points */
|
||||
bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list);
|
||||
bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list);
|
||||
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
||||
@ -360,9 +353,7 @@ public:
|
||||
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
||||
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
||||
|
||||
/*
|
||||
* Grids/Paths
|
||||
*/
|
||||
/* Grids/Paths */
|
||||
uint32 GetFreeGrid(uint16 zoneid);
|
||||
void DeleteGrid(Client *c, uint32 sg2, uint32 grid_num, bool grid_too,uint16 zoneid);
|
||||
void DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num,uint16 zoneid);
|
||||
@ -378,9 +369,7 @@ public:
|
||||
int GetHighestGrid(uint32 zoneid);
|
||||
int GetHighestWaypoint(uint32 zoneid, uint32 gridid);
|
||||
|
||||
/*
|
||||
* NPCs
|
||||
*/
|
||||
/* NPCs */
|
||||
const NPCType* GetNPCType(uint32 id);
|
||||
uint32 NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn = 0, uint32 extra = 0); // 0 = Create 1 = Add; 2 = Update; 3 = Remove; 4 = Delete
|
||||
bool SetSpecialAttkFlag(uint8 id, const char* flag);
|
||||
@ -394,9 +383,7 @@ public:
|
||||
DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID);
|
||||
DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||
|
||||
/*
|
||||
* Mercs
|
||||
*/
|
||||
/* Mercs */
|
||||
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
|
||||
void LoadMercEquipment(Merc *merc);
|
||||
void SaveMercBuffs(Merc *merc);
|
||||
@ -408,9 +395,7 @@ public:
|
||||
//void LoadMercTypesForMercMerchant(NPC *merchant);
|
||||
//void LoadMercsForMercMerchant(NPC *merchant);
|
||||
|
||||
/*
|
||||
* Petitions
|
||||
*/
|
||||
/* Petitions */
|
||||
void UpdateBug(BugStruct* bug);
|
||||
void UpdateBug(PetitionBug_Struct* bug);
|
||||
void DeletePetitionFromDB(Petition* wpet);
|
||||
@ -418,16 +403,11 @@ public:
|
||||
void InsertPetitionToDB(Petition* wpet);
|
||||
void RefreshPetitionsFromDB();
|
||||
|
||||
|
||||
/*
|
||||
* Merchants
|
||||
*/
|
||||
/* Merchants */
|
||||
void SaveMerchantTemp(uint32 npcid, uint32 slot, uint32 item, uint32 charges);
|
||||
void DeleteMerchantTemp(uint32 npcid, uint32 slot);
|
||||
|
||||
/*
|
||||
* Tradeskills
|
||||
*/
|
||||
/* Tradeskills */
|
||||
bool GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec);
|
||||
bool GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec);
|
||||
uint32 GetZoneForage(uint32 ZoneID, uint8 skill); /* for foraging */
|
||||
@ -436,14 +416,10 @@ public:
|
||||
bool EnableRecipe(uint32 recipe_id);
|
||||
bool DisableRecipe(uint32 recipe_id);
|
||||
|
||||
/*
|
||||
* Tribute
|
||||
*/
|
||||
/* Tribute */
|
||||
bool LoadTributes();
|
||||
|
||||
/*
|
||||
* Doors
|
||||
*/
|
||||
/* Doors */
|
||||
bool DoorIsOpen(uint8 door_id,const char* zone_name);
|
||||
void SetDoorPlace(uint8 value,uint8 door_id,const char* zone_name);
|
||||
bool LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version);
|
||||
@ -456,64 +432,46 @@ public:
|
||||
int32 GetDoorsDBCountPlusOne(const char *zone_name, int16 version);
|
||||
void InsertDoor(uint32 did, uint16 ddoorid, const char* ddoor_name, float dxpos, float dypos, float dzpos, float dheading, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize);
|
||||
|
||||
/*
|
||||
* Blocked Spells
|
||||
*/
|
||||
|
||||
/* Blocked Spells */
|
||||
int32 GetBlockedSpellsCount(uint32 zoneid);
|
||||
bool LoadBlockedSpells(int32 blockedSpellsCount, ZoneSpellsBlocked* into, uint32 zoneid);
|
||||
|
||||
/*
|
||||
* Traps
|
||||
*/
|
||||
/* Traps */
|
||||
bool LoadTraps(const char* zonename, int16 version);
|
||||
char* GetTrapMessage(uint32 trap_id);
|
||||
|
||||
/*
|
||||
* Time
|
||||
*/
|
||||
/* Time */
|
||||
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
||||
bool SetZoneTZ(uint32 zoneid, uint32 version, uint32 tz);
|
||||
|
||||
/*
|
||||
* Group
|
||||
*/
|
||||
/* Group */
|
||||
void RefreshGroupFromDB(Client *c);
|
||||
uint8 GroupCount(uint32 groupid);
|
||||
/*
|
||||
* Raid
|
||||
*/
|
||||
|
||||
/* Raid */
|
||||
uint8 RaidGroupCount(uint32 raidid, uint32 groupid);
|
||||
|
||||
/*
|
||||
* Instancing
|
||||
*/
|
||||
/* Instancing */
|
||||
void ListAllInstances(Client* c, uint32 charid);
|
||||
|
||||
/*
|
||||
* QGlobals
|
||||
*/
|
||||
/* QGlobals */
|
||||
void QGlobalPurge();
|
||||
|
||||
/*
|
||||
* Alternate Currency
|
||||
*/
|
||||
/* Alternate Currency */
|
||||
void LoadAltCurrencyValues(uint32 char_id, std::map<uint32, uint32> ¤cy);
|
||||
void UpdateAltCurrencyValue(uint32 char_id, uint32 currency_id, uint32 value);
|
||||
|
||||
/*
|
||||
* Misc stuff.
|
||||
* PLEASE DO NOT ADD TO THIS COLLECTION OF CRAP UNLESS YOUR METHOD
|
||||
* REALLY HAS NO BETTER SECTION
|
||||
* Misc stuff.
|
||||
* PLEASE DO NOT ADD TO THIS COLLECTION OF CRAP UNLESS YOUR METHOD
|
||||
* REALLY HAS NO BETTER SECTION
|
||||
*/
|
||||
bool logevents(const char* accountname,uint32 accountid,uint8 status,const char* charname,const char* target, const char* descriptiontype, const char* description,int event_nid);
|
||||
void GetEventLogs(const char* name,char* target,uint32 account_id=0,uint8 eventid=0,char* detail=0,char* timestamp=0, CharacterEventLog_Struct* cel=0);
|
||||
uint32 GetKarma(uint32 acct_id);
|
||||
void UpdateKarma(uint32 acct_id, uint32 amount);
|
||||
|
||||
/*
|
||||
* Things which really dont belong here...
|
||||
*/
|
||||
/* Things which really dont belong here... */
|
||||
int16 CommandRequirement(const char* commandname);
|
||||
|
||||
protected:
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
#include "../common/debug.h"
|
||||
#include <iostream>
|
||||
#include "entity.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/breakdowns.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
extern EntityList entity_list;
|
||||
|
||||
void DispatchFinishedDBAsync(DBAsyncWork* dbaw) {
|
||||
uint32_breakdown workpt;
|
||||
workpt = dbaw->WPT();
|
||||
switch (workpt.b4()) {
|
||||
case DBA_b4_Entity: {
|
||||
Entity* entity = entity_list.GetID(workpt.w2_3());
|
||||
if (!entity)
|
||||
break;
|
||||
entity->DBAWComplete(workpt.b1(), dbaw);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
std::cout << "Error: DispatchFinishedDBAsync(): Unknown workpt.b4: " << (int) workpt.b4() << ", workpt=" << workpt << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(dbaw);
|
||||
}
|
||||
|
||||
#define MAX_TO_DELETE 10
|
||||
#define MAX_BACKUPS 5
|
||||
bool DBAsyncCB_CharacterBackup(DBAsyncWork* iWork) { // return true means delete data
|
||||
char errbuf[MYSQL_ERRMSG_SIZE] = "dbaq == 0";
|
||||
MYSQL_RES* result = 0;
|
||||
MYSQL_ROW row;
|
||||
char* query = 0;
|
||||
uint32 i;
|
||||
uint8 ToDeleteIndex = 0;
|
||||
uint32 ToDelete[MAX_TO_DELETE];
|
||||
memset(ToDelete, 0, sizeof(ToDelete));
|
||||
|
||||
uint32 BackupAges[MAX_BACKUPS]; // must be sorted, highest value in lowest index
|
||||
memset(BackupAges, 0, sizeof(BackupAges));
|
||||
|
||||
bool FoundBackup[MAX_BACKUPS];
|
||||
memset(FoundBackup, 0, sizeof(FoundBackup));
|
||||
|
||||
BackupAges[0] = 86400;
|
||||
BackupAges[1] = 3600;
|
||||
|
||||
DBAsyncQuery* dbaq = iWork->PopAnswer();
|
||||
if (dbaq && dbaq->GetAnswer(errbuf, &result)) {
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
for (i=0; i<MAX_BACKUPS; i++) {
|
||||
if (BackupAges[i] == 0 || (uint32)atoi(row[1]) > BackupAges[i])
|
||||
i = MAX_BACKUPS;
|
||||
else if (!FoundBackup[i]) {
|
||||
FoundBackup[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_BACKUPS)
|
||||
ToDelete[ToDeleteIndex++] = atoi(row[0]);
|
||||
if (ToDeleteIndex >= MAX_TO_DELETE)
|
||||
break;
|
||||
}
|
||||
if (ToDelete[0]) {
|
||||
uint32 len = 0, size = 0;
|
||||
AppendAnyLenString(&query, &size, &len, "Delete from character_backup where id=%u", ToDelete[0]);
|
||||
for (uint8 i=1; i<ToDeleteIndex; i++) {
|
||||
AppendAnyLenString(&query, &size, &len, " or id=%u", ToDelete[i]);
|
||||
}
|
||||
if (!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in DBAsyncCB_CharacterBackup query2 '%s' %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
bool needtoinsert = false;
|
||||
for (i=0; i<MAX_BACKUPS; i++) {
|
||||
if (BackupAges[i] != 0 && !FoundBackup[i])
|
||||
needtoinsert = true;
|
||||
}
|
||||
if (needtoinsert) {
|
||||
if (!database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"Insert Delayed into character_backup (charid, account_id, name, profile, level, class, x, y, z, zoneid) "
|
||||
"select id, account_id, name, profile, level, class, x, y, z, zoneid "
|
||||
"from character_ where id=%u", iWork->WPT()), errbuf)) {
|
||||
std::cout << "Error in DBAsyncCB_CharacterBackup query3 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// std::cout << "Error in DBAsyncCB_CharacterBackup query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
#ifndef ZONEDBASYNC_H
|
||||
#define ZONEDBASYNC_H
|
||||
|
||||
#include "../common/dbasync.h"
|
||||
void DispatchFinishedDBAsync(DBAsyncWork* iDBAW);
|
||||
bool DBAsyncCB_CharacterBackup(DBAsyncWork* iWork);
|
||||
|
||||
#define DBA_b4_Main 1
|
||||
#define DBA_b4_Worldserver 2
|
||||
#define DBA_b4_Zone 3
|
||||
#define DBA_b4_Entity 4
|
||||
|
||||
#define DBA_b1_Entity_SeeQPT 0
|
||||
#define DBA_b1_Entity_Client_InfoForLogin 1
|
||||
#define DBA_b1_Entity_Client_Save 2
|
||||
#define DBA_b1_Entity_Client_Backup 3
|
||||
#define DBA_b1_Entity_Corpse_Backup 4
|
||||
#define DBA_b1_Zone_MerchantLists 5
|
||||
#define DBA_b1_Zone_MerchantListsTemp 6
|
||||
|
||||
#endif
|
||||
|
||||
@ -50,10 +50,6 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
|
||||
#endif
|
||||
ZoneChange_Struct* zc=(ZoneChange_Struct*)app->pBuffer;
|
||||
|
||||
printf("INCOMING CLIENT\n\n");
|
||||
printf("%s\n", zc->char_name);
|
||||
printf("%u\n", zc->zoneID);
|
||||
|
||||
uint16 target_zone_id = 0;
|
||||
uint16 target_instance_id = zc->instanceID;
|
||||
ZonePoint* zone_point = nullptr;
|
||||
@ -568,7 +564,6 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
|
||||
|
||||
if(ReadyToZone) {
|
||||
zone_mode = zm;
|
||||
printf("\n\n ZONE MODE %u \n\n", zm);
|
||||
if(zm == ZoneToBindPoint) {
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + iZoneNameLength);
|
||||
ZonePlayerToBind_Struct* gmg = (ZonePlayerToBind_Struct*) outapp->pBuffer;
|
||||
@ -602,10 +597,6 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
|
||||
gmg->instance_id = instance_id;
|
||||
gmg->type = 0x01; //an observed value, not sure of meaning
|
||||
|
||||
printf("gmg->zone_id %u \n", gmg->zone_id);
|
||||
printf("gmg->x %u \n", gmg->x);
|
||||
printf("gmg->y %u \n", gmg->y);
|
||||
|
||||
outapp->priority = 6;
|
||||
FastQueuePacket(&outapp);
|
||||
safe_delete(outapp);
|
||||
@ -726,6 +717,7 @@ void Client::SetBindPoint(int to_zone, float new_x, float new_y, float new_z) {
|
||||
m_pp.binds[0].y = new_y;
|
||||
m_pp.binds[0].z = new_z;
|
||||
}
|
||||
database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, 0, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0);
|
||||
}
|
||||
|
||||
void Client::GoToBind(uint8 bindnum) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user