eqemu-server/queryserv/database.cpp
akkadius 7f89191ffc Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015'
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
2014-08-23 23:59:20 -05:00

304 lines
12 KiB
C++

/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
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 <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include <map>
#include <vector>
// Disgrace: for windows compile
#ifdef _WINDOWS
#include <windows.h>
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include "../common/unix.h"
#include <netinet/in.h>
#endif
#include "database.h"
#include "../common/eq_packet_structs.h"
#include "../common/string_util.h"
#include "../common/servertalk.h"
Database::Database ()
{
DBInitVars();
}
/*
Establish a connection to a mysql database with the supplied parameters
*/
Database::Database(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
{
DBInitVars();
Connect(host, user, passwd, database, port);
}
bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
{
uint32 errnum= 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf))
{
LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
HandleMysqlError(errnum);
return false;
}
else
{
LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
return true;
}
}
void Database::DBInitVars() {
}
void Database::HandleMysqlError(uint32 errnum) {
}
/*
Close the connection to the database
*/
Database::~Database()
{
}
void Database::AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
char *S1 = new char[strlen(from) * 2 + 1];
char *S2 = new char[strlen(to) * 2 + 1];
char *S3 = new char[strlen(message) * 2 + 1];
DoEscapeString(S1, from, strlen(from));
DoEscapeString(S2, to, strlen(to));
DoEscapeString(S3, message, strlen(message));
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_speech` SET `from`='%s', `to`='%s', `message`='%s', `minstatus`='%i', `guilddbid`='%i', `type`='%i'", S1, S2, S3, minstatus, guilddbid, type), errbuf, 0, 0)) {
_log(QUERYSERV__ERROR, "Failed Speech Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
safe_delete_array(query);
safe_delete_array(S1);
safe_delete_array(S2);
safe_delete_array(S3);
}
void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_trade_record` SET `time`=NOW(), "
"`char1_id`='%i', `char1_pp`='%i', `char1_gp`='%i', `char1_sp`='%i', `char1_cp`='%i', `char1_items`='%i', "
"`char2_id`='%i', `char2_pp`='%i', `char2_gp`='%i', `char2_sp`='%i', `char2_cp`='%i', `char2_items`='%i'",
QS->char1_id, QS->char1_money.platinum, QS->char1_money.gold, QS->char1_money.silver, QS->char1_money.copper, QS->char1_count,
QS->char2_id, QS->char2_money.platinum, QS->char2_money.gold, QS->char2_money.silver, QS->char2_money.copper, QS->char2_count),
errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Trade Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Items > 0) {
for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_trade_record_entries` SET `event_id`='%i', "
"`from_id`='%i', `from_slot`='%i', `to_id`='%i', `to_slot`='%i', `item_id`='%i', "
"`charges`='%i', `aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].from_id, QS->items[i].from_slot, QS->items[i].to_id, QS->items[i].to_slot, QS->items[i].item_id,
QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed Trade Log Record Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
}
void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_handin_record` SET `time`=NOW(), `quest_id`='%i', "
"`char_id`='%i', `char_pp`='%i', `char_gp`='%i', `char_sp`='%i', `char_cp`='%i', `char_items`='%i', "
"`npc_id`='%i', `npc_pp`='%i', `npc_gp`='%i', `npc_sp`='%i', `npc_cp`='%i', `npc_items`='%i'",
QS->quest_id, QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count,
QS->npc_id, QS->npc_money.platinum, QS->npc_money.gold, QS->npc_money.silver, QS->npc_money.copper, QS->npc_count),
errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Handin Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Items > 0) {
for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_handin_record_entries` SET `event_id`='%i', "
"`action_type`='%s', `char_slot`='%i', `item_id`='%i', `charges`='%i', "
"`aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].action_type, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges,
QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed Handin Log Record Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
}
void Database::LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members){
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record` SET `npc_id`='%i', `type`='%i', `zone_id`='%i', `time`=NOW()", QS->s1.NPCID, QS->s1.Type, QS->s1.ZoneID), errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed NPC Kill Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Members > 0){
for (int i = 0; i < Members; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_npc_kill_record_entries` SET `event_id`='%i', `char_id`='%i'", lastid, QS->Chars[i].char_id, errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed NPC Kill Log Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
}
void Database::LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_delete_record` SET `time`=NOW(), "
"`char_id`='%i', `stack_size`='%i', `char_items`='%i'",
QS->char_id, QS->stack_size, QS->char_count, QS->char_count),
errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Delete Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Items > 0) {
for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_delete_record_entries` SET `event_id`='%i', "
"`char_slot`='%i', `item_id`='%i', `charges`='%i', `aug_1`='%i', "
"`aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1,
QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed Delete Log Record Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
}
void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items) {
/* These are item moves */
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_move_record` SET `time`=NOW(), "
"`char_id`='%i', `from_slot`='%i', `to_slot`='%i', `stack_size`='%i', `char_items`='%i', `postaction`='%i'",
QS->char_id, QS->from_slot, QS->to_slot, QS->stack_size, QS->char_count, QS->postaction),
errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Move Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Items > 0) {
for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_move_record_entries` SET `event_id`='%i', "
"`from_slot`='%i', `to_slot`='%i', `item_id`='%i', `charges`='%i', "
"`aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'", lastid,
QS->items[i].from_slot, QS->items[i].to_slot, QS->items[i].item_id, QS->items[i].charges,
QS->items[i].aug_1, QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed Move Log Record Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
}
void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items) {
/* Merchant transactions are from the perspective of the merchant, not the player -U */
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_merchant_transaction_record` SET `time`=NOW(), "
"`zone_id`='%i', `merchant_id`='%i', `merchant_pp`='%i', `merchant_gp`='%i', `merchant_sp`='%i', `merchant_cp`='%i', `merchant_items`='%i', "
"`char_id`='%i', `char_pp`='%i', `char_gp`='%i', `char_sp`='%i', `char_cp`='%i', `char_items`='%i'",
QS->zone_id, QS->merchant_id, QS->merchant_money.platinum, QS->merchant_money.gold, QS->merchant_money.silver, QS->merchant_money.copper, QS->merchant_count,
QS->char_id, QS->char_money.platinum, QS->char_money.gold, QS->char_money.silver, QS->char_money.copper, QS->char_count),
errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Transaction Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
if(Items > 0) {
for(int i = 0; i < Items; i++) {
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_merchant_transaction_record_entries` SET `event_id`='%i', "
"`char_slot`='%i', `item_id`='%i', `charges`='%i', `aug_1`='%i', "
"`aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
lastid, QS->items[i].char_slot, QS->items[i].item_id, QS->items[i].charges, QS->items[i].aug_1,
QS->items[i].aug_2, QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5,
errbuf, 0, 0))) {
_log(QUERYSERV__ERROR, "Failed Transaction Log Record Entry Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
}
}
safe_delete_array(query);
}
void Database::GeneralQueryReceive(ServerPacket *pack) {
/*
These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again
*/
char *Query = nullptr;
Query = new char[pack->ReadUInt32() + 1];
pack->ReadString(Query);
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
uint32 lastid = 0;
if (!RunQuery(query, MakeAnyLenString(&query, Query), errbuf, 0, 0, &lastid)) {
_log(QUERYSERV__ERROR, "Failed Delete Log Record Insert: %s", errbuf);
_log(QUERYSERV__ERROR, "%s", query);
}
safe_delete_array(query);
safe_delete(pack);
safe_delete(Query);
}