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:
Akkadius
2014-09-04 07:24:17 -05:00
parent 0a9222e1ee
commit 4432c07081
37 changed files with 1235 additions and 2370 deletions
-2
View File
@@ -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
+691 -663
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -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();
-669
View File
@@ -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
View File
@@ -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
+9 -6
View File
@@ -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
+1
View File
@@ -32,6 +32,7 @@ MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, u
void MySQLRequestResult::FreeInternals()
{
safe_delete_array(m_ErrorBuffer);
if (m_Result != nullptr)
+1 -1
View File
@@ -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;}
+28 -79
View File
@@ -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;
-3
View File
@@ -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
*/