mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload
intensive or metric based logging to a remote server process that could exist on another server entirely
Implemented Player Event Logging Types (Go to table `qs_player_events`):
1 = Player_Log_Quest,
2 = Player_Log_Zoning,
3 = Player_Log_Deaths,
4 = Player_Log_Connect_State,
5 = Player_Log_Levels,
6 = Player_Log_Keyring_Addition,
7 = Player_Log_QGlobal_Update,
8 = Player_Log_Task_Updates,
9 = Player_Log_AA_Purchases,
10 = Player_Log_Trade_Skill_Events,
11 = Player_Log_Issued_Commands,
12 = Player_Log_Money_Transactions,
13 = Player_Log_Alternate_Currency_Transactions,
- All QueryServ logging will be implemented with a front end in EoC 2.0 very soon
Changed all QS Error related logging to 'QUERYSERV__ERROR'
(Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE (
Implemented Perl Quest objects (LUA still needed to be exported):
- quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging
- quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events`
Added MySQL Tables:
- `qs_player_aa_rate_hourly`
- `qs_player_events`
- Source table structures from:
- utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly
To get the complete QueryServ schema, source from here:
- utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql
Added rules for each logging type, source rules here with them enabled by default:
- utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql
Spawn related logging cleanup
General code cleanup
Added queryserv.cpp and queryserv.h with QueryServ class
311 lines
9.7 KiB
C++
311 lines
9.7 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include "../common/debug.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#ifdef _WINDOWS
|
|
#include <process.h>
|
|
#else
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#ifdef _WINDOWS
|
|
#define snprintf _snprintf
|
|
#define strncasecmp _strnicmp
|
|
#define strcasecmp _stricmp
|
|
#endif
|
|
#include "../common/string_util.h"
|
|
#include "../common/packet_functions.h"
|
|
#include "../common/packet_dump.h"
|
|
#include "../common/packet_dump_file.h"
|
|
#include "../common/emu_opcodes.h"
|
|
#include "../common/eq_packet_structs.h"
|
|
#include "../common/servertalk.h"
|
|
#include "entity.h"
|
|
#include "masterentity.h"
|
|
|
|
#include "petitions.h"
|
|
#include "worldserver.h"
|
|
|
|
PetitionList petition_list;
|
|
|
|
extern WorldServer worldserver;
|
|
|
|
|
|
void Petition::SendPetitionToPlayer(Client* clientto) {
|
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionCheckout,sizeof(Petition_Struct));
|
|
Petition_Struct* pet = (Petition_Struct*) outapp->pBuffer;
|
|
strcpy(pet->accountid,this->GetAccountName());
|
|
strcpy(pet->lastgm,this->GetLastGM());
|
|
strcpy(pet->charname,this->GetCharName());
|
|
pet->petnumber = this->petid;
|
|
pet->charclass = this->GetCharClass();
|
|
pet->charlevel = this->GetCharLevel();
|
|
pet->charrace = this->GetCharRace();
|
|
pet->zone = this->GetZone();
|
|
//strcpy(pet->zone,this->GetZone());
|
|
strcpy(pet->petitiontext,this->GetPetitionText());
|
|
pet->checkouts = this->GetCheckouts();
|
|
pet->unavail = this->GetUnavails();
|
|
pet->senttime = this->GetSentTime();
|
|
//memset(pet->unknown5, 0, sizeof(pet->unknown5));
|
|
//pet->unknown5[3] = 0x1f;
|
|
pet->urgency = this->GetUrgency();
|
|
strcpy(pet->gmtext, this->GetGMText());
|
|
clientto->QueuePacket(outapp);
|
|
safe_delete(outapp);
|
|
return;
|
|
}
|
|
|
|
Petition::Petition(uint32 id)
|
|
{
|
|
petid = id;
|
|
charclass = 0;
|
|
charrace = 0;
|
|
charlevel = 0;
|
|
checkouts = 0;
|
|
unavailables = 0;
|
|
urgency = 0;
|
|
time(&senttime);
|
|
ischeckedout = false;
|
|
memset(accountname, 0, sizeof(accountname));
|
|
memset(charname, 0, sizeof(charname));
|
|
memset(lastgm, 0, sizeof(lastgm));
|
|
memset(petitiontext, 0, sizeof(petitiontext));
|
|
memset(gmtext, 0, sizeof(gmtext));
|
|
|
|
//memset(this->zone, 0, sizeof(this->zone));
|
|
zone = 1;
|
|
}
|
|
Petition* PetitionList::GetPetitionByID(uint32 id_in) {
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements()) {
|
|
if (iterator.GetData()->GetID() == id_in)
|
|
return iterator.GetData();
|
|
iterator.Advance();
|
|
}
|
|
return 0;
|
|
}
|
|
uint32 PetitionList::GetTotalPetitions(){
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
iterator.Reset();
|
|
uint32 total=0;
|
|
while(iterator.MoreElements()) {
|
|
total++;
|
|
iterator.Advance();
|
|
}
|
|
return total;
|
|
}
|
|
bool PetitionList::FindPetitionByAccountName(const char* acctname) {
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements()) {
|
|
if (!strcmp(acctname,iterator.GetData()->GetAccountName()))
|
|
return true;
|
|
iterator.Advance();
|
|
}
|
|
return false;
|
|
}
|
|
bool PetitionList::DeletePetitionByCharName(const char* charname) {
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements()) {
|
|
if (!strcmp(charname,iterator.GetData()->GetCharName())) {
|
|
if(DeletePetition(iterator.GetData()->GetID())==0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
iterator.Advance();
|
|
}
|
|
return false;
|
|
}
|
|
void PetitionList::UpdateZoneListQueue() {
|
|
ServerPacket* pack = new ServerPacket(ServerOP_Petition, sizeof(ServerPetitionUpdate_Struct));
|
|
ServerPetitionUpdate_Struct* pupdate = (ServerPetitionUpdate_Struct*) pack->pBuffer;
|
|
pupdate->petid = 0x00;
|
|
pupdate->status = 0x00;
|
|
worldserver.SendPacket(pack);
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void PetitionList::AddPetition(Petition* pet) {
|
|
list.Insert(pet);
|
|
return;
|
|
}
|
|
|
|
//Return Values: 0 = Ok ; -1 = Error deleting petition.
|
|
int PetitionList::DeletePetition(uint32 petnumber) {
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
iterator.Reset();
|
|
LockMutex lock(&PList_Mutex);
|
|
while(iterator.MoreElements()) {
|
|
if (iterator.GetData()->GetID() == petnumber) {
|
|
database.DeletePetitionFromDB(iterator.GetData());
|
|
iterator.RemoveCurrent();
|
|
return 0;
|
|
break;
|
|
}
|
|
else {
|
|
iterator.Advance();
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void PetitionList::UpdateGMQueue() {
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
iterator.Reset();
|
|
uint32 total=0;
|
|
while(iterator.MoreElements()) {
|
|
total++;
|
|
entity_list.SendPetitionToAdmins(iterator.GetData());
|
|
iterator.Advance();
|
|
}
|
|
if(total==0)
|
|
entity_list.SendPetitionToAdmins();
|
|
return;
|
|
}
|
|
|
|
void PetitionList::ClearPetitions() {
|
|
// entity_list.ClearClientPetitionQueue();
|
|
LinkedListIterator<Petition*> iterator(list);
|
|
iterator.Reset();
|
|
while(iterator.MoreElements())
|
|
{
|
|
iterator.RemoveCurrent(true);
|
|
iterator.Advance();
|
|
}
|
|
return;
|
|
}
|
|
|
|
void PetitionList::ReadDatabase() {
|
|
LockMutex lock(&PList_Mutex);
|
|
ClearPetitions();
|
|
database.RefreshPetitionsFromDB();
|
|
UpdateGMQueue();
|
|
return;
|
|
}
|
|
|
|
void PetitionList::UpdatePetition(Petition* pet) {
|
|
LockMutex lock(&PList_Mutex);
|
|
database.UpdatePetitionToDB(pet);
|
|
return;
|
|
}
|
|
|
|
void ZoneDatabase::DeletePetitionFromDB(Petition* wpet) {
|
|
|
|
std::string query = StringFormat("DELETE FROM petitions WHERE petid = %i", wpet->GetID());
|
|
auto results = QueryDatabase(query);
|
|
if (!results.Success())
|
|
LogFile->write(EQEMuLog::Error, "Error in DeletePetitionFromDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
|
|
|
}
|
|
|
|
void ZoneDatabase::UpdatePetitionToDB(Petition* wpet) {
|
|
|
|
std::string query = StringFormat("UPDATE petitions SET gmtext = '%s', lastgm = '%s', urgency = %i, "
|
|
"checkouts = %i, unavailables = %i, ischeckedout = %i "
|
|
"WHERE petid = %i",
|
|
wpet->GetGMText(), wpet->GetLastGM(), wpet->GetUrgency(),
|
|
wpet->GetCheckouts(), wpet->GetUnavails(),
|
|
wpet->CheckedOut() ? 1: 0, wpet->GetID());
|
|
auto results = QueryDatabase(query);
|
|
if (!results.Success())
|
|
LogFile->write(EQEMuLog::Error, "Error in UpdatePetitionToDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
|
|
|
}
|
|
|
|
void ZoneDatabase::InsertPetitionToDB(Petition* wpet)
|
|
{
|
|
|
|
uint32 len = strlen(wpet->GetPetitionText());
|
|
char* petitiontext = new char[2*len+1];
|
|
memset(petitiontext, 0, 2*len+1);
|
|
DoEscapeString(petitiontext, wpet->GetPetitionText(), len);
|
|
|
|
std::string query = StringFormat("INSERT INTO petitions "
|
|
"(petid, charname, accountname, lastgm, "
|
|
"petitiontext, zone, urgency, charclass, "
|
|
"charrace, charlevel, checkouts, unavailables, "
|
|
"ischeckedout, senttime, gmtext) "
|
|
"VALUES (%i, '%s', '%s', '%s', '%s', "
|
|
"%i, %i, %i, %i, %i, "
|
|
"%i, %i, %i, %i, '%s')",
|
|
wpet->GetID(), wpet->GetCharName(), wpet->GetAccountName(), wpet->GetLastGM(),
|
|
petitiontext, wpet->GetZone(), wpet->GetUrgency(), wpet->GetCharClass(),
|
|
wpet->GetCharRace(), wpet->GetCharLevel(), wpet->GetCheckouts(), wpet->GetUnavails(),
|
|
wpet->CheckedOut()? 1: 0, wpet->GetSentTime(), wpet->GetGMText());
|
|
safe_delete_array(petitiontext);
|
|
auto results = QueryDatabase(query);
|
|
if (!results.Success()) {
|
|
LogFile->write(EQEMuLog::Error, "Error in InsertPetitionToDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return;
|
|
}
|
|
|
|
#if EQDEBUG >= 5
|
|
LogFile->write(EQEMuLog::Debug, "New petition created");
|
|
#endif
|
|
|
|
}
|
|
|
|
void ZoneDatabase::RefreshPetitionsFromDB()
|
|
{
|
|
Petition* newpet;
|
|
std::string query = "SELECT petid, charname, accountname, lastgm, petitiontext, "
|
|
"zone, urgency, charclass, charrace, charlevel, checkouts, "
|
|
"unavailables, ischeckedout, senttime, gmtext "
|
|
"FROM petitions ORDER BY petid";
|
|
auto results = QueryDatabase(query);
|
|
if (!results.Success()) {
|
|
LogFile->write(EQEMuLog::Error, "Error in RefreshPetitionsFromDB query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return;
|
|
}
|
|
|
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
|
newpet = new Petition(atoi(row[0]));
|
|
newpet->SetCName(row[1]);
|
|
newpet->SetAName(row[2]);
|
|
newpet->SetLastGM(row[3]);
|
|
newpet->SetPetitionText(row[4]);
|
|
newpet->SetZone(atoi(row[5]));
|
|
newpet->SetUrgency(atoi(row[6]));
|
|
newpet->SetClass(atoi(row[7]));
|
|
newpet->SetRace(atoi(row[8]));
|
|
newpet->SetLevel(atoi(row[9]));
|
|
newpet->SetCheckouts(atoi(row[10]));
|
|
newpet->SetUnavails(atoi(row[11]));
|
|
newpet->SetSentTime2(atol(row[13]));
|
|
newpet->SetGMText(row[14]);
|
|
|
|
if (atoi(row[12]) == 1)
|
|
newpet->SetCheckedOut(true);
|
|
else
|
|
newpet->SetCheckedOut(false);
|
|
petition_list.AddPetition(newpet);
|
|
}
|
|
|
|
}
|