From 5fec840f0696282b169968b41fbc55d484cf05ee Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 13:58:36 -0700 Subject: [PATCH 01/57] AssignWaypoints converted to QueryDatabase --- zone/waypoints.cpp | 135 +++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 77 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index eb22f13a8..d0da194e8 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -869,97 +869,78 @@ void NPC::AssignWaypoints(int32 grid) { return; } - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - bool GridErr = false, WPErr = false; Waypoints.clear(); + roamer = false; // Retrieve the wander and pause types for this grid - if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `type`,`type2` FROM `grid` WHERE `id`=%i AND `zoneid`=%i",grid,zone->GetZoneID()),errbuf, &result)) - { - if((row = mysql_fetch_row(result))) - { - if(row[0] != 0) - wandertype = atoi(row[0]); - else - wandertype = 0; - if(row[1] != 0) - pausetype = atoi(row[1]); - else - pausetype = 0; - } - else // No grid record found in this zone for the given ID - GridErr = true; - mysql_free_result(result); + std::string query = StringFormat("SELECT `type`, `type2` FROM `grid` WHERE `id` = %i AND `zoneid` = %i", grid, zone->GetZoneID()); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str()); + return; } - else // DB query error! - { - GridErr = true; - LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, errbuf); - } - safe_delete_array(query); - if(!GridErr) - { - this->CastToNPC()->SetGrid(grid); // Assign grid number + if (results.RowCount() == 0) + return; - // Retrieve all waypoints for this grid - if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z`,`pause`,`heading` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result)) - { - roamer = true; - max_wp = -1; // Initialize it; will increment it for each waypoint successfully added to the list + auto row = results.begin(); - while((row = mysql_fetch_row(result))) - { - if(row[0] != 0 && row[1] != 0 && row[2] != 0 && row[3] != 0) - { - wplist newwp; - newwp.index = ++max_wp; - newwp.x = atof(row[0]); - newwp.y = atof(row[1]); - newwp.z = atof(row[2]); + wandertype = atoi(row[0]); + pausetype = atoi(row[1]); - if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) ) - { - if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() || - (zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z))) - { - Map::Vertex dest(newwp.x, newwp.y, newwp.z); - float newz = zone->zonemap->FindBestZ(dest, nullptr); + this->CastToNPC()->SetGrid(grid); // Assign grid number - if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading)) - newwp.z = newz + 1; - } - } + // Retrieve all waypoints for this grid + query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` " + "FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i " + "ORDER BY `number`", grid, zone->GetZoneID()); + results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str()); + return; + } + + roamer = true; + max_wp = 0; // Initialize it; will increment it for each waypoint successfully added to the list + + for (auto row = results.begin(); row != results.end(); ++row, ++max_wp) + { + wplist newwp; + newwp.index = max_wp; + newwp.x = atof(row[0]); + newwp.y = atof(row[1]); + newwp.z = atof(row[2]); + + if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) ) + { + if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() || + (zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z))) + { + Map::Vertex dest(newwp.x, newwp.y, newwp.z); + + float newz = zone->zonemap->FindBestZ(dest, nullptr); + + if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading)) + newwp.z = newz + 1; + } + } + + newwp.pause = atoi(row[3]); + newwp.heading = atof(row[4]); + Waypoints.push_back(newwp); + } - newwp.pause = atoi(row[3]); - newwp.heading = atof(row[4]); - Waypoints.push_back(newwp); - } - } - mysql_free_result(result); - } - else // DB query error! - { - WPErr = true; - LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, errbuf); - } - safe_delete_array(query); - } // end if (!GridErr) if(Waypoints.size() < 2) { roamer = false; - } else if(!GridErr && !WPErr) { - UpdateWaypoint(0); - SetWaypointPause(); - if (wandertype == 1 || wandertype == 2 || wandertype == 5) - CalculateNewWaypoint(); - } else { - roamer = false; } + + UpdateWaypoint(0); + SetWaypointPause(); + + if (wandertype == 1 || wandertype == 2 || wandertype == 5) + CalculateNewWaypoint(); + } void Mob::SendTo(float new_x, float new_y, float new_z) { From b6547293839be356c004051e1fe7e6fb95470722 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:03:00 -0700 Subject: [PATCH 02/57] GetGridType2 converted to QueryDatabase --- zone/waypoints.cpp | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index d0da194e8..44f8d061f 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1030,24 +1030,21 @@ int ZoneDatabase::GetHighestGrid(uint32 zoneid) { } uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) { - char *query = 0; - char errbuff[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - int type2 = 0; - if (RunQuery(query, MakeAnyLenString(&query,"SELECT type2 from grid where id = %i and zoneid = %i",grid,zoneid),errbuff,&result)) { - safe_delete_array(query); - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - type2 = atoi( row[0] ); - } - mysql_free_result(result); - } else { - LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query, errbuff); - safe_delete_array(query); - } - return(type2); + int type2 = 0; + std::string query = StringFormat("SELECT type2 FROM grid WHERE id = %i AND zoneid = %i", grid, zoneid); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return 0; + } + + if (results.RowCount() != 1) + return 0; + + auto row = results.begin(); + + return atoi(row[0]); } bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) { From 5f2db0d1cbef149585eb01d95c4e3df95d0aef90 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:08:43 -0700 Subject: [PATCH 03/57] GetWaypoints converted to QueryDatabase --- zone/waypoints.cpp | 48 ++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 44f8d061f..c3a1331fb 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1048,31 +1048,29 @@ uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) { } bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) { - char *query = 0; - char errbuff[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - if (RunQuery(query, MakeAnyLenString(&query,"SELECT x, y, z, pause, heading from grid_entries where gridid = %i and number = %i and zoneid = %i",grid,num,zoneid),errbuff,&result)) { - safe_delete_array(query); - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - if ( wp ) { - wp->x = atof( row[0] ); - wp->y = atof( row[1] ); - wp->z = atof( row[2] ); - wp->pause = atoi( row[3] ); - wp->heading = atof( row[4] ); - } - mysql_free_result(result); - return true; - } - mysql_free_result(result); - } - else { - LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query, errbuff); - safe_delete_array(query); - } - return false; + + std::string query = StringFormat("SELECT x, y, z, pause, heading FROM grid_entries " + "WHERE gridid = %i AND number = %i AND zoneid = %i", grid, num, zoneid); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return false; + } + + if (results.RowCount() != 1) + return false; + + auto row = results.begin(); + + if (wp) { + wp->x = atof( row[0] ); + wp->y = atof( row[1] ); + wp->z = atof( row[2] ); + wp->pause = atoi( row[3] ); + wp->heading = atof( row[4] ); + } + + return true; } void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid) From cab0beb77f21b502b0e441c3b38e6d1eaff5a210 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:32:04 -0700 Subject: [PATCH 04/57] AssignGrid converted to QueryDatabase --- zone/waypoints.cpp | 155 ++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 93 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index c3a1331fb..46304b31e 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1049,6 +1049,9 @@ uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) { bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) { + if (wp == nullptr) + return false; + std::string query = StringFormat("SELECT x, y, z, pause, heading FROM grid_entries " "WHERE gridid = %i AND number = %i AND zoneid = %i", grid, num, zoneid); auto results = QueryDatabase(query); @@ -1062,122 +1065,88 @@ bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* auto row = results.begin(); - if (wp) { - wp->x = atof( row[0] ); - wp->y = atof( row[1] ); - wp->z = atof( row[2] ); - wp->pause = atoi( row[3] ); - wp->heading = atof( row[4] ); - } + wp->x = atof(row[0]); + wp->y = atof(row[1]); + wp->z = atof(row[2]); + wp->pause = atoi(row[3]); + wp->heading = atof(row[4]); return true; } void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid) { - char *query = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; int matches = 0, fuzzy = 0, spawn2id = 0; - uint32 affected_rows; float dbx = 0, dby = 0; // looks like most of the stuff in spawn2 is straight integers // so let's try that first - if(!RunQuery( - query, - MakeAnyLenString( - &query, - "SELECT id,x,y FROM spawn2 WHERE zone='%s' AND x=%i AND y=%i", - zone->GetShortName(), (int)x, (int)y - ), - errbuf, - &result - )) { - LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query, errbuf); - return; + std::string query = StringFormat("SELECT id, x, y FROM spawn2 WHERE zone = '%s' AND x = %i AND y = %i", + zone->GetShortName(), (int)x, (int)y); + auto results = QueryDatabase(query); + if(!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + return; } - safe_delete_array(query); // how much it's allowed to be off by #define _GASSIGN_TOLERANCE 1.0 - if(!(matches = mysql_num_rows(result))) // try a fuzzy match if that didn't find it + if(results.RowCount() == 0) // try a fuzzy match if that didn't find it { - mysql_free_result(result); - if(!RunQuery( - query, - MakeAnyLenString( - &query, - "SELECT id,x,y FROM spawn2 WHERE zone='%s' AND " - "ABS( ABS(x) - ABS(%f) ) < %f AND " - "ABS( ABS(y) - ABS(%f) ) < %f", - zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE - ), - errbuf, - &result - )) { - LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query, errbuf); + query = StringFormat("SELECT id,x,y FROM spawn2 WHERE zone='%s' AND " + "ABS( ABS(x) - ABS(%f) ) < %f AND " + "ABS( ABS(y) - ABS(%f) ) < %f", + zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE); + results = QueryDatabase(query); + if(!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); return; } - safe_delete_array(query); + fuzzy = 1; - if(!(matches = mysql_num_rows(result))) - mysql_free_result(result); + matches = results.RowCount(); } - if(matches) + + if (matches == 0) { + client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2"); + return; + } + + if(matches == 1) { - if(matches > 1) - { - client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match"); - mysql_free_result(result); - } - else - { - row = mysql_fetch_row(result); - spawn2id = atoi(row[0]); - dbx = atof(row[1]); - dby = atof(row[2]); - if(!RunQuery( - query, - MakeAnyLenString( - &query, - "UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id - ), - errbuf, - &result, - &affected_rows - )) { - LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query, errbuf); - return; - } - if(affected_rows == 1) - { - if(client) client->LogSQL(query); - if(fuzzy) - { - float difference; - difference = sqrtf(pow(fabs(x-dbx),2) + pow(fabs(y-dby),2)); - client->Message(0, - "Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f", - spawn2id, difference - ); - } - else - { - client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id); - } - } - else - { - client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id); - } - } + client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match"); + return; } - else + + auto row = results.begin(); + + spawn2id = atoi(row[0]); + dbx = atof(row[1]); + dby = atof(row[2]); + + query = StringFormat("UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id); + results = QueryDatabase(query); + if (!results.Success()) { - client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2"); - } + LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + return; + } + + if (results.RowsAffected() != 1) { + client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id); + return; + } + + if(client) + client->LogSQL(query.c_str()); + + if(!fuzzy) { + client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id); + return; + } + + float difference = sqrtf(pow(fabs(x - dbx) , 2) + pow(fabs(y - dby), 2)); + client->Message(0, "Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f", spawn2id, difference); } /****************** From 334e29a6d66ce6815fbe19b336f335cb547a09ab Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:40:47 -0700 Subject: [PATCH 05/57] ModifyGrid converted to QueryDatabase --- zone/waypoints.cpp | 56 ++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 46304b31e..571cb5e13 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1156,41 +1156,43 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid) * type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted) * zoneid: The ID number of the zone the grid is being created/deleted in */ +void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) { -void ZoneDatabase::ModifyGrid(Client *c, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) { - char *query = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; if (!remove) { - if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid(id,zoneid,type,type2) VALUES(%i,%i,%i,%i)",id,zoneid,type,type2), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); + std::string query = StringFormat("INSERT INTO grid(id, zoneid, type, type2) " + "VALUES (%i, %i, %i, %i)", id, zoneid, type, type2); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + return; + } + + if(client) + client->LogSQL(query.c_str()); + + return; } - else - { - if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid where id=%i",id), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); - query = 0; - if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries WHERE zoneid=%i AND gridid=%i",zoneid,id), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); - } -} /*** END ZoneDatabase::ModifyGrid() ***/ + + std::string query = StringFormat("DELETE FROM grid where id=%i", id); + auto results = QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + else if(client) + client->LogSQL(query.c_str()); + + query = StringFormat("DELETE FROM grid_entries WHERE zoneid = %i AND gridid = %i", zoneid, id); + results = QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + else if(client) + client->LogSQL(query.c_str()); + +} /************************************** * AddWP - Adds a new waypoint to a specific grid for a specific zone. */ - void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading) { char *query = 0; From 06b0bd6da45c1d4f0a05d0c7fba19535585640b5 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:44:32 -0700 Subject: [PATCH 06/57] AddWP converted to QueryDatabase --- zone/waypoints.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 571cb5e13..a4a4ba40a 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1193,18 +1193,20 @@ void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type /************************************** * AddWP - Adds a new waypoint to a specific grid for a specific zone. */ -void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading) +void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading) { - char *query = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; - - if(!RunQuery(query,MakeAnyLenString(&query,"INSERT INTO grid_entries (gridid,zoneid,`number`,x,y,z,pause,heading) values (%i,%i,%i,%f,%f,%f,%i,%f)",gridid,zoneid,wpnum,xpos,ypos,zpos,pause,heading), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); + std::string query = StringFormat("INSERT INTO grid_entries (gridid, zoneid, `number`, x, y, z, pause, heading) " + "VALUES (%i, %i, %i, %f, %f, %f, %i, %f)", + gridid, zoneid, wpnum, xpos, ypos, zpos, pause, heading); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + return; } - safe_delete_array(query); -} /*** END ZoneDatabase::AddWP() ***/ + + if(client) + client->LogSQL(query.c_str()); +} /********** From c466317082eaa945c4c4eb2e891a861b186b48c0 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 14:48:57 -0700 Subject: [PATCH 07/57] DeleteWaypoint converted to QueryDatabase --- zone/waypoints.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index a4a4ba40a..81d5c4ed4 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1219,19 +1219,20 @@ void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, float xpos * wp_num: The number of the waypoint being deleted * zoneid: The ID number of the zone that contains the waypoint being deleted */ - -void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uint16 zoneid) +void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num, uint16 zoneid) { - char *query=0; - char errbuf[MYSQL_ERRMSG_SIZE]; - - if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries where gridid=%i and zoneid=%i and `number`=%i",grid_num,zoneid,wp_num), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); + std::string query = StringFormat("DELETE FROM grid_entries WHERE " + "gridid = %i AND zoneid = %i AND `number` = %i", + grid_num, zoneid, wp_num); + auto results = QueryDatabase(query); + if(!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + return; } - safe_delete_array(query); -} /*** END ZoneDatabase::DeleteWaypoint() ***/ + + if(client) + client->LogSQL(query.c_str()); +} /****************** From 8b69de46e9309ac019b459a01bdd8c8523aa2e69 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 15:06:53 -0700 Subject: [PATCH 08/57] AddWPForSpawn converted to QueryDatabase --- zone/waypoints.cpp | 121 ++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 81d5c4ed4..111d091e4 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1242,92 +1242,77 @@ void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num * Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of * the created grid is returned. */ +uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) { -uint32 ZoneDatabase::AddWPForSpawn(Client *c, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) { - char *query = 0; - uint32 grid_num, // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating) - next_wp_num; // The waypoint number we should be assigning to the new waypoint - bool CreatedNewGrid; // Did we create a new grid in this function? - MYSQL_RES *result; - MYSQL_ROW row; - char errbuf[MYSQL_ERRMSG_SIZE]; + uint32 grid_num; // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating) + uint32 next_wp_num; // The waypoint number we should be assigning to the new waypoint + bool createdNewGrid; // Did we create a new grid in this function? // See what grid number our spawn is assigned - if(RunQuery(query, MakeAnyLenString(&query,"SELECT pathgrid FROM spawn2 WHERE id=%i",spawn2id),errbuf,&result)) - { - safe_delete_array(query); - if(mysql_num_rows(result) > 0) - { - row = mysql_fetch_row(result); - grid_num = atoi(row[0]); - } - else // This spawn ID was not found in the `spawn2` table - return 0; - - mysql_free_result(result); - } - else { // Query error - LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query, errbuf); + std::string query = StringFormat("SELECT pathgrid FROM spawn2 WHERE id = %i", spawn2id); + auto results = QueryDatabase(query); + if (!results.Success()) { + // Query error + LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); return 0; } - if (grid_num == 0) // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn - { - CreatedNewGrid = true; - if((grid_num = GetFreeGrid(zoneid)) == 0) // There are no grids for the current zone -- create Grid #1 - grid_num = 1; + if (results.RowCount() == 0) + return 0; - if(!RunQuery(query, MakeAnyLenString(&query,"insert into grid set id='%i',zoneid= %i, type='%i', type2='%i'",grid_num,zoneid,type1,type2), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); + auto row = results.begin(); + grid_num = atoi(row[0]); - query = 0; - if(!RunQuery(query, MakeAnyLenString(&query,"update spawn2 set pathgrid='%i' where id='%i'",grid_num,spawn2id), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); + if (grid_num == 0) + { // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn + createdNewGrid = true; + grid_num = GetFreeGrid(zoneid); + if(grid_num == 0) // There are no grids for the current zone -- create Grid #1 + grid_num = 1; + + query = StringFormat("INSERT INTO grid SET id = '%i', zoneid = %i, type ='%i', type2 = '%i'", + grid_num, zoneid, type1, type2); + results = QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + else if(client) + client->LogSQL(query.c_str()); + + query = StringFormat("UPDATE spawn2 SET pathgrid = '%i' WHERE id = '%i'", grid_num, spawn2id); + results = QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + else if(client) + client->LogSQL(query.c_str()); } else // NPC had a grid assigned to it - CreatedNewGrid = false; - + createdNewGrid = false; // Find out what the next waypoint is for this grid - query = 0; - if(RunQuery(query, MakeAnyLenString(&query,"SELECT max(`number`) FROM grid_entries WHERE zoneid='%i' AND gridid='%i'",zoneid,grid_num),errbuf,&result)) - { - safe_delete_array(query); - row = mysql_fetch_row(result); - if(row[0] != 0) - next_wp_num = atoi(row[0]) + 1; - else // No waypoints in this grid yet - next_wp_num = 1; + query = StringFormat("SELECT max(`number`) FROM grid_entries WHERE zoneid = '%i' AND gridid = '%i'", zoneid, grid_num); - mysql_free_result(result); - } - else { // Query error - LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query, errbuf); + if(!results.Success()) { // Query error + LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); return 0; } - query = 0; - if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid_entries(gridid,zoneid,`number`,x,y,z,pause,heading) VALUES (%i,%i,%i,%f,%f,%f,%i,%f)",grid_num,zoneid,next_wp_num,xpos,ypos,zpos,pause,heading), errbuf)) { - LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query, errbuf); - } else { - if(c) c->LogSQL(query); - } - safe_delete_array(query); + row = results.begin(); + if(row[0] != 0) + next_wp_num = atoi(row[0]) + 1; + else // No waypoints in this grid yet + next_wp_num = 1; - if(CreatedNewGrid) - return grid_num; - - return 0; -} /*** END ZoneDatabase::AddWPForSpawn() ***/ + query = StringFormat("INSERT INTO grid_entries(gridid, zoneid, `number`, x, y, z, pause, heading) " + "VALUES (%i, %i, %i, %f, %f, %f, %i, %f)", + grid_num, zoneid, next_wp_num, xpos, ypos, zpos, pause, heading); + results = QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str()); + else if(client) + client->LogSQL(query.c_str()); + return createdNewGrid? grid_num: 0; +} uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { char *query = 0; From 2f30488cd55af2cad3716b8d955a3d706d831331 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 15:11:12 -0700 Subject: [PATCH 09/57] GetFreeGrid converted to QueryDatabase --- zone/waypoints.cpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 111d091e4..a67943b5c 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1315,28 +1315,22 @@ uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, float xpos, } uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { - char *query = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - if (RunQuery(query, MakeAnyLenString(&query,"SELECT max(id) from grid where zoneid = %i",zoneid),errbuf,&result)) { - safe_delete_array(query); - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - uint32 tmp=0; - if (row[0]) - tmp = atoi(row[0]); - mysql_free_result(result); - tmp++; - return tmp; - } - mysql_free_result(result); + + std::string query = StringFormat("SELECT max(id) FROM grid WHERE zoneid = %i", zoneid); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return 0; } - else { - LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query, errbuf); - safe_delete_array(query); - } - return 0; + + if (results.RowCount() != 1) + return 0; + + auto row = results.begin(); + uint32 freeGridID = 1; + freeGridID = atoi(row[0]) + 1; + + return freeGridID; } int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) { From fe718a81f3ed6bbff96ed8082a0918bd789d0ee0 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 20 Aug 2014 15:14:36 -0700 Subject: [PATCH 10/57] GetHighestWaypoint converted to QueryDatabase --- zone/waypoints.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index a67943b5c..2119ea384 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -1334,26 +1334,20 @@ uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { } int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) { - char *query = 0; - char errbuff[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - int res = 0; - if (RunQuery(query, MakeAnyLenString(&query, - "SELECT COALESCE(MAX(number), 0) FROM grid_entries WHERE zoneid = %i AND gridid = %i", - zoneid, gridid),errbuff,&result)) { - safe_delete_array(query); - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - res = atoi( row[0] ); - } - mysql_free_result(result); - } else { - LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query, errbuff); - safe_delete_array(query); + + std::string query = StringFormat("SELECT COALESCE(MAX(number), 0) FROM grid_entries " + "WHERE zoneid = %i AND gridid = %i", zoneid, gridid); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return 0; } - return(res); + if (results.RowCount() != 1) + return 0; + + auto row = results.begin(); + return atoi(row[0]); } void NPC::SaveGuardSpotCharm() From 9a5d2d2bc575b34f4a8464e4db2501d7a6a365d0 Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 22 Aug 2014 20:48:11 -0400 Subject: [PATCH 11/57] Trade Stacking: BETA --- changelog.txt | 10 + common/item.cpp | 93 ++++++++ common/item.h | 1 + zone/common.h | 2 +- zone/inventory.cpp | 21 +- zone/trading.cpp | 533 ++++++++++++++++++++++++++++++--------------- 6 files changed, 475 insertions(+), 185 deletions(-) diff --git a/changelog.txt b/changelog.txt index bf2ea97f0..9d593e3e2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,15 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 08/22/2014 == +Uleat: Rework of Trade::FinishedTrade() and Trade::ResetTrade() to parse items a little more intelligently. + +Trade window items are now sent to client inventory in this order: + - Bags + - Partial stack movements + - All remaining items + +If any of these procedures cause any problems, please post them immediately. + == 08/20/2014 == Uleat: Rework of Trade::AddEntity() - function used to move items into the trade window. Now accepts argument for 'stack_size' and updates client properly. Note: I tested trade with Titanium:{SoF,SoD,UF,RoF} in both directions and no client generated an OP_MoveItem event for attempting to place a stackable diff --git a/common/item.cpp b/common/item.cpp index 7d6618335..bbb6f14f8 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -654,6 +654,99 @@ int16 Inventory::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, boo return INVALID_INDEX; } +// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function... +int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { + // Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade(). + // If you have a need, use it..but, understand it is not a compatible replacement for Inventory::FindFreeSlot(). + // + // I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias -U + + if (!inst || !inst->GetID()) + return INVALID_INDEX; + + // step 1: find room for bags (caller should really ask for slots for bags first to avoid sending them to cursor..and bag item loss) + if (inst->IsType(ItemClassContainer)) { + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) + if (!m_inv[free_slot]) + return free_slot; + + return MainCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...) + } + + // step 2: find partial room for stackables + if (inst->IsStackable()) { + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + const ItemInst* main_inst = m_inv[free_slot]; + + if (!main_inst) + continue; + + if ((main_inst->GetID() == inst->GetID()) && (main_inst->GetCharges() < main_inst->GetItem()->StackSize)) + return free_slot; + + if (main_inst->IsType(ItemClassContainer)) { // if item-specific containers already have bad items, we won't fix it here... + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { + const ItemInst* sub_inst = main_inst->GetItem(free_bag_slot); + + if (!sub_inst) + continue; + + if ((sub_inst->GetID() == inst->GetID()) && (sub_inst->GetCharges() < sub_inst->GetItem()->StackSize)) + return Inventory::CalcSlotId(free_slot, free_bag_slot); + } + } + } + } + + // step 3a: find room for container-specific items (ItemClassArrow) + if (inst->GetItem()->ItemType == ItemTypeArrow) { + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + const ItemInst* main_inst = m_inv[free_slot]; + + if (!main_inst || (main_inst->GetItem()->BagType != BagTypeQuiver) || !main_inst->IsType(ItemClassContainer)) + continue; + + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + if (!main_inst->GetItem(free_bag_slot)) + return Inventory::CalcSlotId(free_slot, free_bag_slot); + } + } + + // step 3b: find room for container-specific items (ItemClassSmallThrowing) + if (inst->GetItem()->ItemType == ItemTypeSmallThrowing) { + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + const ItemInst* main_inst = m_inv[free_slot]; + + if (!main_inst || (main_inst->GetItem()->BagType != BagTypeBandolier) || !main_inst->IsType(ItemClassContainer)) + continue; + + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + if (!main_inst->GetItem(free_bag_slot)) + return Inventory::CalcSlotId(free_slot, free_bag_slot); + } + } + + // step 4: just find an empty slot + for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + const ItemInst* main_inst = m_inv[free_slot]; + + if (!main_inst) + return free_slot; + + if (main_inst->IsType(ItemClassContainer)) { + if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver)) + continue; + + for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) + if (!main_inst->GetItem(free_bag_slot)) + return Inventory::CalcSlotId(free_slot, free_bag_slot); + } + } + + //return INVALID_INDEX; // everything else pushes to the cursor + return MainCursor; +} + // Opposite of below: Get parent bag slot_id from a slot inside of bag int16 Inventory::CalcSlotId(int16 slot_id) { int16 parent_slot_id = INVALID_INDEX; diff --git a/common/item.h b/common/item.h index ef59ddd6f..f279bd2aa 100644 --- a/common/item.h +++ b/common/item.h @@ -172,6 +172,7 @@ public: // Locate an available inventory slot int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false); + int16 FindFreeSlotForTradeItem(const ItemInst* inst); // Calculate slot_id for an item within a bag static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id diff --git a/zone/common.h b/zone/common.h index 3cc1af1cf..eccffec62 100644 --- a/zone/common.h +++ b/zone/common.h @@ -526,7 +526,7 @@ public: Mob* With(); // Add item from cursor slot to trade bucket (automatically does bag data too) - void AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size); + void AddEntity(uint16 trade_slot_id, uint32 stack_size); // Audit trade void LogTrade(); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 5c5f80122..197841c76 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -822,25 +822,24 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) return database.SaveCursor(CharacterID(), s, e); } -bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) -{ +bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) { mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id); + if (slot_id == MainCursor) - { - return PushItemOnCursor(inst,client_update); - } + return PushItemOnCursor(inst, client_update); else m_inv.PutItem(slot_id, inst); - if (client_update) { - SendItemPacket(slot_id, &inst, (slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade); - } + if (client_update) + SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade)); if (slot_id == MainCursor) { - std::list::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end(); + std::list::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end(); return database.SaveCursor(this->CharacterID(), s, e); - } else + } + else { return database.SaveInventory(this->CharacterID(), &inst, slot_id); + } CalcBonuses(); } @@ -1539,7 +1538,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Also sends trade information to other client of trade session if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit - trade->AddEntity(src_slot_id, dst_slot_id, move_in->number_in_stack); + trade->AddEntity(dst_slot_id, move_in->number_in_stack); return true; } else { diff --git a/zone/trading.cpp b/zone/trading.cpp index 1efcbbb33..1ae9596b9 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -71,8 +71,8 @@ void Trade::Start(uint32 mob_id, bool initiate_with) } // Add item from a given slot to trade bucket (automatically does bag data too) -void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size) { - // TODO: review for inventory saves +void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { + // TODO: review for inventory saves / consider changing return type to bool so failure can be passed to desync handler if (!owner || !owner->IsClient()) { // This should never happen @@ -121,7 +121,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si if (_stack_size > 0) inst->SetCharges(_stack_size); else - client->DeleteItemInInventory(from_slot_id); + client->DeleteItemInInventory(MainCursor); SendItemData(inst2, trade_slot_id); } @@ -136,7 +136,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si _log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id); client->PutItemInInventory(trade_slot_id, *inst); - client->DeleteItemInInventory(from_slot_id); + client->DeleteItemInInventory(MainCursor); } } @@ -316,206 +316,393 @@ void Trade::DumpTrade() #endif void Client::ResetTrade() { - const Item_Struct* TempItem = 0; - ItemInst* ins; - int x; AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true); - for(x = EmuConstants::TRADE_BEGIN; x <= EmuConstants::TRADE_END; x++) - { - TempItem = 0; - ins = GetInv().GetItem(x); - if (ins) - TempItem = ins->GetItem(); - if (TempItem) - { - bool is_arrow = (TempItem->ItemType == ItemTypeArrow) ? true : false; - int freeslotid = GetInv().FindFreeSlot(ins->IsType(ItemClassContainer), true, TempItem->Size, is_arrow); - if (freeslotid == INVALID_INDEX) - { - DropInst(ins); + + // step 1: process bags + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + const ItemInst* inst = m_inv[trade_slot]; + + if (inst && inst->IsType(ItemClassContainer)) { + int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst); + + if (free_slot != INVALID_INDEX) { + PutItemInInventory(free_slot, *inst); + SendItemPacket(free_slot, inst, ItemPacketTrade); } - else - { - PutItemInInventory(freeslotid, *ins); - SendItemPacket(freeslotid, ins, ItemPacketTrade); + else { + DropInst(inst); } - DeleteItemInInventory(x); + + DeleteItemInInventory(trade_slot); + } + } + + // step 2a: process stackables + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + ItemInst* inst = GetInv().GetItem(trade_slot); + + if (inst && inst->IsStackable()) { + while (true) { + // there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks + int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst); + + if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX)) + break; + + ItemInst* partial_inst = GetInv().GetItem(free_slot); + + if (!partial_inst) + break; + + if (partial_inst->GetID() != inst->GetID()) { + _log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()"); + + break; + } + + if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) { + int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize; + + partial_inst->SetCharges(partial_inst->GetItem()->StackSize); + inst->SetCharges(new_charges); + } + else { + partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges()); + inst->SetCharges(0); + } + + PutItemInInventory(free_slot, *partial_inst); + SendItemPacket(free_slot, partial_inst, ItemPacketTrade); + + if (inst->GetCharges() == 0) { + DeleteItemInInventory(trade_slot); + + break; + } + } + } + } + + // step 2b: adjust trade stack bias + // (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur) + for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) { + ItemInst* inst = GetInv().GetItem(trade_slot); + + if (inst && inst->IsStackable()) { + for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) { + if (bias_slot >= trade_slot) + break; + + ItemInst* bias_inst = GetInv().GetItem(bias_slot); + + if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize)) + continue; + + if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) { + int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize; + + bias_inst->SetCharges(bias_inst->GetItem()->StackSize); + inst->SetCharges(new_charges); + } + else { + bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges()); + inst->SetCharges(0); + } + + if (inst->GetCharges() == 0) { + DeleteItemInInventory(trade_slot); + + break; + } + } + } + } + + // step 3: process everything else + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + const ItemInst* inst = m_inv[trade_slot]; + + if (inst) { + int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst); + + if (free_slot != INVALID_INDEX) { + PutItemInInventory(free_slot, *inst); + SendItemPacket(free_slot, inst, ItemPacketTrade); + } + else { + DropInst(inst); + } + + DeleteItemInInventory(trade_slot); } } } void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) { - if(tradingWith && tradingWith->IsClient()) { Client* other = tradingWith->CastToClient(); if(other) { mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName()); - int16 slot_id; - const Item_Struct* item = nullptr; - QSPlayerLogTrade_Struct* qsaudit = nullptr; - bool QSPLT = false; - - // QS code - if(qspack && RuleB(QueryServ, PlayerLogTrades)) { - qsaudit = (QSPlayerLogTrade_Struct*) qspack->pBuffer; - QSPLT = true; - - if(finalizer) { qsaudit->char2_id = this->character_id; } - else { qsaudit->char1_id = this->character_id; } - } - - // Move each trade slot into free inventory slot - for(int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){ - const ItemInst* inst = m_inv[i]; - uint16 parent_offset = 0; - - if(inst == nullptr) { continue; } - - mlog(TRADING__CLIENT, "Giving %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, i, other->GetName()); - - /// Log Player Trades through QueryServ if Rule Enabled - if(QSPLT) { - uint16 item_count = qsaudit->char1_count + qsaudit->char2_count; - parent_offset = item_count; - - qsaudit->items[item_count].from_id = this->character_id; - qsaudit->items[item_count].from_slot = i; - qsaudit->items[item_count].to_id = other->CharacterID(); - qsaudit->items[item_count].to_slot = 0; - qsaudit->items[item_count].item_id = inst->GetID(); - qsaudit->items[item_count].charges = inst->GetCharges(); - qsaudit->items[item_count].aug_1 = inst->GetAugmentItemID(1); - qsaudit->items[item_count].aug_2 = inst->GetAugmentItemID(2); - qsaudit->items[item_count].aug_3 = inst->GetAugmentItemID(3); - qsaudit->items[item_count].aug_4 = inst->GetAugmentItemID(4); - qsaudit->items[item_count].aug_5 = inst->GetAugmentItemID(5); - - if(finalizer) { qsaudit->char2_count++; } - else { qsaudit->char1_count++; } - - if(inst->IsType(ItemClassContainer)) { - // Pseudo-Slot ID's are generated based on how the db saves bag items... - for(uint8 j = SUB_BEGIN; j < inst->GetItem()->BagSlots; j++) { - const ItemInst* baginst = inst->GetItem(j); - - if(baginst == nullptr) { continue; } - - int16 k=Inventory::CalcSlotId(i, j); - item_count = qsaudit->char1_count + qsaudit->char2_count; - - qsaudit->items[item_count].from_id = this->character_id; - qsaudit->items[item_count].from_slot = k; - qsaudit->items[item_count].to_id = other->CharacterID(); - qsaudit->items[item_count].to_slot = 0; - qsaudit->items[item_count].item_id = baginst->GetID(); - qsaudit->items[item_count].charges = baginst->GetCharges(); - qsaudit->items[item_count].aug_1 = baginst->GetAugmentItemID(1); - qsaudit->items[item_count].aug_2 = baginst->GetAugmentItemID(2); - qsaudit->items[item_count].aug_3 = baginst->GetAugmentItemID(3); - qsaudit->items[item_count].aug_4 = baginst->GetAugmentItemID(4); - qsaudit->items[item_count].aug_5 = baginst->GetAugmentItemID(5); - - if(finalizer) { qsaudit->char2_count++; } - else { qsaudit->char1_count++; } - } - } - } - - if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) { - bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; - slot_id = other->GetInv().FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); - - mlog(TRADING__CLIENT, "Trying to put %s (%d) into slot %d", inst->GetItem()->Name, inst->GetItem()->ID, slot_id); - - if(other->PutItemInInventory(slot_id, *inst, true)) { - mlog(TRADING__CLIENT, "Item %s (%d) successfully transfered, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); - - if(QSPLT) { - qsaudit->items[parent_offset].to_slot = slot_id; - - if(inst->IsType(ItemClassContainer)) { - for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) { - const ItemInst* bag_inst = inst->GetItem(bagslot_idx); - - if(bag_inst == nullptr) { continue; } - int16 to_bagslot_id = Inventory::CalcSlotId(slot_id, bagslot_idx); - - qsaudit->items[++parent_offset].to_slot = to_bagslot_id; - } - } - } - } - else { - PushItemOnCursor(*inst, true); - mlog(TRADING__ERROR, "Unable to give item %d (%d) to %s, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName()); - - if(QSPLT) { - qsaudit->items[parent_offset].to_id = this->character_id; - qsaudit->items[parent_offset].to_slot = MainCursor; - - if(inst->IsType(ItemClassContainer)) { - for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) { - const ItemInst* bag_inst = inst->GetItem(bagslot_idx); - - if(bag_inst == nullptr) { continue; } - int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx); - - qsaudit->items[++parent_offset].to_id = this->character_id; - qsaudit->items[parent_offset].to_slot = to_bagslot_id; - } - } - } - } - - DeleteItemInInventory(i); - } - else { - PushItemOnCursor(*inst, true); - DeleteItemInInventory(i); - - if(QSPLT) { - qsaudit->items[parent_offset].to_id = this->character_id; - qsaudit->items[parent_offset].to_slot = MainCursor; - - if(inst->IsType(ItemClassContainer)) { - for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) { - const ItemInst* bag_inst = inst->GetItem(bagslot_idx); - - if(bag_inst == nullptr) { continue; } - int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx); - - qsaudit->items[++parent_offset].to_id = this->character_id; - qsaudit->items[parent_offset].to_slot = to_bagslot_id; - } - } - } - } - } - - // Money - look into how NPC's receive cash this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true); - // This is currently setup to show character offers, not receipts - if(QSPLT) { - if(finalizer) { + // step 0: pre-processing + // QS code + if (qspack && RuleB(QueryServ, PlayerLogTrades)) { + QSPlayerLogTrade_Struct* qsaudit = (QSPlayerLogTrade_Struct*)qspack->pBuffer; + + if (finalizer) { + qsaudit->char2_id = this->character_id; + qsaudit->char2_money.platinum = this->trade->pp; qsaudit->char2_money.gold = this->trade->gp; qsaudit->char2_money.silver = this->trade->sp; qsaudit->char2_money.copper = this->trade->cp; } else { - qsaudit->char1_money.platinum = this->trade->pp; + qsaudit->char1_id = this->character_id; + + qsaudit->char1_money.platinum = this->trade->pp; qsaudit->char1_money.gold = this->trade->gp; qsaudit->char1_money.silver = this->trade->sp; qsaudit->char1_money.copper = this->trade->cp; } + + // qsaudit->items[x].to_slot is disabled until QueryServ:PlayerLogTrades code is updated + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + const ItemInst* inst = m_inv[trade_slot]; + + if (!inst) + continue; + + uint16 item_offset = qsaudit->char1_count + qsaudit->char2_count; + + qsaudit->items[item_offset].from_id = this->character_id; + qsaudit->items[item_offset].from_slot = trade_slot; + qsaudit->items[item_offset].to_id = other->CharacterID(); + qsaudit->items[item_offset].to_slot = 0; // disabled + qsaudit->items[item_offset].item_id = inst->GetID(); + qsaudit->items[item_offset].charges = inst->GetCharges(); + qsaudit->items[item_offset].aug_1 = inst->GetAugmentItemID(1); + qsaudit->items[item_offset].aug_2 = inst->GetAugmentItemID(2); + qsaudit->items[item_offset].aug_3 = inst->GetAugmentItemID(3); + qsaudit->items[item_offset].aug_4 = inst->GetAugmentItemID(4); + qsaudit->items[item_offset].aug_5 = inst->GetAugmentItemID(5); + + if (finalizer) + ++qsaudit->char2_count; + else + ++qsaudit->char1_count; + + if (inst->IsType(ItemClassContainer)) { + // Pseudo-Slot ID's are generated based on how the db saves bag items... + for (uint8 sub_slot = SUB_BEGIN; sub_slot < inst->GetItem()->BagSlots; ++sub_slot) { + const ItemInst* sub_inst = inst->GetItem(sub_slot); + + if (!sub_inst) + continue; + + int16 from_slot = Inventory::CalcSlotId(trade_slot, sub_slot); + item_offset = qsaudit->char1_count + qsaudit->char2_count; + + qsaudit->items[item_offset].from_id = this->character_id; + qsaudit->items[item_offset].from_slot = from_slot; + qsaudit->items[item_offset].to_id = other->CharacterID(); + qsaudit->items[item_offset].to_slot = 0; // disabled + qsaudit->items[item_offset].item_id = sub_inst->GetID(); + qsaudit->items[item_offset].charges = sub_inst->GetCharges(); + qsaudit->items[item_offset].aug_1 = sub_inst->GetAugmentItemID(1); + qsaudit->items[item_offset].aug_2 = sub_inst->GetAugmentItemID(2); + qsaudit->items[item_offset].aug_3 = sub_inst->GetAugmentItemID(3); + qsaudit->items[item_offset].aug_4 = sub_inst->GetAugmentItemID(4); + qsaudit->items[item_offset].aug_5 = sub_inst->GetAugmentItemID(5); + + if (finalizer) + ++qsaudit->char2_count; + else + ++qsaudit->char1_count; + } + } + } + } + + // step 1: process bags + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + const ItemInst* inst = m_inv[trade_slot]; + + if (inst && inst->IsType(ItemClassContainer)) { + mlog(TRADING__CLIENT, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName()); + + // TODO: need to check bag items/augments for no drop..everything for attuned... + if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) { + int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst); + + if (free_slot != INVALID_INDEX) { + if (other->PutItemInInventory(free_slot, *inst, true)) { + mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); + } + else { + mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName()); + + PushItemOnCursor(*inst, true); + } + } + else { + mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID); + + PushItemOnCursor(*inst, true); + } + } + else { + mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID); + + PushItemOnCursor(*inst, true); + } + + DeleteItemInInventory(trade_slot); + } + } + + // step 2a: process stackables + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + ItemInst* inst = GetInv().GetItem(trade_slot); + + if (inst && inst->IsStackable()) { + while (true) { + // there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks + int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst); + + if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX)) + break; + + ItemInst* partial_inst = other->GetInv().GetItem(partial_slot); + + if (!partial_inst) + break; + + if (partial_inst->GetID() != inst->GetID()) { + _log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()"); + + break; + } + + int16 old_charges = inst->GetCharges(); + int16 partial_charges = partial_inst->GetCharges(); + + if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) { + int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize; + + partial_inst->SetCharges(partial_inst->GetItem()->StackSize); + inst->SetCharges(new_charges); + } + else { + partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges()); + inst->SetCharges(0); + } + + mlog(TRADING__CLIENT, "Transferring partial stack %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName()); + + if (other->PutItemInInventory(partial_slot, *partial_inst, true)) { + mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.", + inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges())); + } + else { + mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.", + inst->GetItem()->Name, inst->GetItem()->ID, other->GetName(), (old_charges - inst->GetCharges())); + + inst->SetCharges(old_charges); + partial_inst->SetCharges(partial_charges); + + break; + } + + if (inst->GetCharges() == 0) { + DeleteItemInInventory(trade_slot); + + break; + } + } + } + } + + // step 2b: adjust trade stack bias + // (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur) + for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) { + ItemInst* inst = GetInv().GetItem(trade_slot); + + if (inst && inst->IsStackable()) { + for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) { + if (bias_slot >= trade_slot) + break; + + ItemInst* bias_inst = GetInv().GetItem(bias_slot); + + if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize)) + continue; + + if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) { + int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize; + + bias_inst->SetCharges(bias_inst->GetItem()->StackSize); + inst->SetCharges(new_charges); + } + else { + bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges()); + inst->SetCharges(0); + } + + if (inst->GetCharges() == 0) { + DeleteItemInInventory(trade_slot); + + break; + } + } + } + } + + // step 3: process everything else + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + const ItemInst* inst = m_inv[trade_slot]; + + if (inst) { + mlog(TRADING__CLIENT, "Giving item %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName()); + + // TODO: need to check bag items/augments for no drop..everything for attuned... + if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) { + int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst); + + if (free_slot != INVALID_INDEX) { + if (other->PutItemInInventory(free_slot, *inst, true)) { + mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); + } + else { + mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName()); + + PushItemOnCursor(*inst, true); + } + } + else { + mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID); + + PushItemOnCursor(*inst, true); + } + } + else { + mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID); + + PushItemOnCursor(*inst, true); + } + + DeleteItemInInventory(trade_slot); + } } //Do not reset the trade here, done by the caller. } } + + // trading with npc doesn't require Inventory::FindFreeSlotForTradeItem() rework else if(tradingWith && tradingWith->IsNPC()) { QSPlayerLogHandin_Struct* qsaudit = nullptr; bool QSPLH = false; From a568a6f1947d54ded73acfa6113321284d0fc8c4 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:10:30 -0700 Subject: [PATCH 12/57] GetAccountStatus converted to QueryDatabase --- ucs/database.cpp | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 4d055e2a4..c71601cdf 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -102,41 +102,34 @@ Database::~Database() { } -void Database::GetAccountStatus(Client *c) { - - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!RunQuery(query,MakeAnyLenString(&query, "select `status`, `hideme`, `karma`, `revoked` from `account` where `id`='%i' limit 1", - c->GetAccountID()),errbuf,&result)){ - - _log(UCS__ERROR, "Unable to get account status for character %s, error %s", c->GetName().c_str(), errbuf); - - safe_delete_array(query); +void Database::GetAccountStatus(Client *client) { + std::string query = StringFormat("SELECT `status`, `hideme`, `karma`, `revoked` " + "FROM `account` WHERE `id` = '%i' LIMIT 1", + client->GetAccountID()); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "Unable to get account status for character %s, error %s", client->GetName().c_str(), results.ErrorMessage().c_str()); return; } - _log(UCS__TRACE, "GetAccountStatus Query: %s", query); - safe_delete_array(query); - if(mysql_num_rows(result) != 1) + _log(UCS__TRACE, "GetAccountStatus Query: %s", query.c_str()); + + if(results.RowCount() != 1) { _log(UCS__ERROR, "Error in GetAccountStatus"); - mysql_free_result(result); return; } - row = mysql_fetch_row(result); + auto row = results.begin(); - c->SetAccountStatus(atoi(row[0])); - c->SetHideMe(atoi(row[1]) != 0); - c->SetKarma(atoi(row[2])); - c->SetRevoked((atoi(row[3])==1?true:false)); + client->SetAccountStatus(atoi(row[0])); + client->SetHideMe(atoi(row[1]) != 0); + client->SetKarma(atoi(row[2])); + client->SetRevoked((atoi(row[3])==1?true:false)); + + _log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", client->GetAccountStatus(), client->GetHideMe(), client->GetKarma(), client->GetName().c_str()); - _log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", c->GetAccountStatus(), c->GetHideMe(), c->GetKarma(), c->GetName().c_str()); - mysql_free_result(result); } int Database::FindAccount(const char *CharacterName, Client *c) { From 5c640b2d4007ba23bbec76dc0797f394ad5e17dd Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:16:05 -0700 Subject: [PATCH 13/57] FindAccount converted to QueryDatabase --- ucs/database.cpp | 61 ++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index c71601cdf..2ac80bda2 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -132,55 +132,44 @@ void Database::GetAccountStatus(Client *client) { } -int Database::FindAccount(const char *CharacterName, Client *c) { +int Database::FindAccount(const char *characterName, Client *client) { - _log(UCS__TRACE, "FindAccount for character %s", CharacterName); + _log(UCS__TRACE, "FindAccount for character %s", characterName); - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - c->ClearCharacters(); - - if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `account_id`, `level` from `character_` where `name`='%s' limit 1", - CharacterName),errbuf,&result)) - { - _log(UCS__ERROR, "FindAccount query failed: %s", query); - safe_delete_array(query); + client->ClearCharacters(); + std::string query = StringFormat("SELECT `id`, `account_id`, `level` " + "FROM `character_` WHERE `name` = '%s' LIMIT 1", + characterName); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "FindAccount query failed: %s", query.c_str()); return -1; } - safe_delete_array(query); - if (mysql_num_rows(result) != 1) - { + if (results.RowCount() != 1) { _log(UCS__ERROR, "Bad result from query"); - mysql_free_result(result); return -1; } - row = mysql_fetch_row(result); - c->AddCharacter(atoi(row[0]), CharacterName, atoi(row[2])); - int AccountID = atoi(row[1]); + auto row = results.begin(); + client->AddCharacter(atoi(row[0]), characterName, atoi(row[2])); - mysql_free_result(result); - _log(UCS__TRACE, "Account ID for %s is %i", CharacterName, AccountID); + int accountID = atoi(row[1]); - if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `name`, `level` from `character_` where `account_id`=%i and `name` !='%s'", - AccountID, CharacterName),errbuf,&result)) - { - safe_delete_array(query); - return AccountID; - } - safe_delete_array(query); + _log(UCS__TRACE, "Account ID for %s is %i", characterName, accountID); - for(unsigned int i = 0; i < mysql_num_rows(result); i++) - { - row = mysql_fetch_row(result); - c->AddCharacter(atoi(row[0]), row[1], atoi(row[2])); - } - mysql_free_result(result); - return AccountID; + query = StringFormat("SELECT `id`, `name`, `level` FROM `character_` " + "WHERE `account_id` = %i AND `name` != '%s'", + accountID, characterName); + results = QueryDatabase(query); + if (!results.Success()) + return accountID; + + for (auto row = results.begin(); row != results.end(); ++row) + client->AddCharacter(atoi(row[0]), row[1], atoi(row[2])); + + return accountID; } bool Database::VerifyMailKey(std::string CharacterName, int IPAddress, std::string MailKey) { From 6b90f883cd7ed30fca2d3c37242c8671d773f449 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:18:47 -0700 Subject: [PATCH 14/57] VerifyMailKey converted to QueryDatabase --- ucs/database.cpp | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 2ac80bda2..6d2606fd7 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -172,45 +172,31 @@ int Database::FindAccount(const char *characterName, Client *client) { return accountID; } -bool Database::VerifyMailKey(std::string CharacterName, int IPAddress, std::string MailKey) { - - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!RunQuery(query,MakeAnyLenString(&query, "select `mailkey` from `character_` where `name`='%s' limit 1", - CharacterName.c_str()),errbuf,&result)){ - - safe_delete_array(query); - - _log(UCS__ERROR, "Error retrieving mailkey from database: %s", errbuf); +bool Database::VerifyMailKey(std::string characterName, int IPAddress, std::string MailKey) { + std::string query = StringFormat("SELECT `mailkey` FROM `character_` WHERE `name`='%s' LIMIT 1", + characterName.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "Error retrieving mailkey from database: %s", results.ErrorMessage().c_str()); return false; } - safe_delete_array(query); - - row = mysql_fetch_row(result); + auto row = results.begin(); // The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated // by world. // - char CombinedKey[17]; + char combinedKey[17]; if(RuleB(Chat, EnableMailKeyIPVerification) == true) - sprintf(CombinedKey, "%08X%s", IPAddress, MailKey.c_str()); + sprintf(combinedKey, "%08X%s", IPAddress, MailKey.c_str()); else - sprintf(CombinedKey, "%s", MailKey.c_str()); + sprintf(combinedKey, "%s", MailKey.c_str()); - _log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], CombinedKey); - - bool Valid = !strcmp(row[0], CombinedKey); - - mysql_free_result(result); - - return Valid; + _log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], combinedKey); + return !strcmp(row[0], combinedKey); } int Database::FindCharacter(const char *CharacterName) { From de477553206230350d6ca6988c5cc0d7979def13 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:24:28 -0700 Subject: [PATCH 15/57] FindCharacter converted to QueryDatabase --- ucs/database.cpp | 48 +++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 6d2606fd7..28eb93af5 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -199,46 +199,28 @@ bool Database::VerifyMailKey(std::string characterName, int IPAddress, std::stri return !strcmp(row[0], combinedKey); } -int Database::FindCharacter(const char *CharacterName) { +int Database::FindCharacter(const char *characterName) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - char *SafeCharName = RemoveApostrophes(CharacterName); - - if (!RunQuery(query,MakeAnyLenString(&query, "select `id` from `character_` where `name`='%s' limit 1", - SafeCharName),errbuf,&result)){ - - _log(UCS__ERROR, "FindCharacter failed. %s %s", query, errbuf); - - safe_delete_array(query); - safe_delete_array(SafeCharName); + char *safeCharName = RemoveApostrophes(characterName); + std::string query = StringFormat("SELECT `id` FROM `character_` WHERE `name`='%s' LIMIT 1", safeCharName); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "FindCharacter failed. %s %s", query.c_str(), results.ErrorMessage().c_str()); + safe_delete(safeCharName); + return -1; + } + safe_delete(safeCharName); + if (results.RowCount() != 1) { + _log(UCS__ERROR, "Bad result from FindCharacter query for character %s", characterName); return -1; } - safe_delete_array(query); - safe_delete_array(SafeCharName); + auto row = results.begin(); - if (mysql_num_rows(result) != 1) { - - _log(UCS__ERROR, "Bad result from FindCharacter query for character %s", CharacterName); - - mysql_free_result(result); - - return -1; - } - - row = mysql_fetch_row(result); - - int CharacterID = atoi(row[0]); - - mysql_free_result(result); - - return CharacterID; + int characterID = atoi(row[0]); + return characterID; } bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { From 19486bac0d2e253aa0b6a90699b7198d0237f51a Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:27:18 -0700 Subject: [PATCH 16/57] GetVariable converted to QueryDatabase --- ucs/database.cpp | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 28eb93af5..155ee986a 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -225,35 +225,20 @@ int Database::FindCharacter(const char *characterName) { bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!RunQuery(query,MakeAnyLenString(&query, "select `value` from `variables` where `varname`='%s'", varname), errbuf, &result)) { - - _log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf); - - safe_delete_array(query); - + std::string query = StringFormat("SELECT `value` FROM `variables` WHERE `varname` = '%s'", varname); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - safe_delete_array(query); - - if (mysql_num_rows(result) != 1) { - - mysql_free_result(result); - + if (results.RowCount() != 1) return false; - } - row = mysql_fetch_row(result); + auto row = results.begin(); snprintf(varvalue, varvalue_len, "%s", row[0]); - mysql_free_result(result); - return true; } From 76fdfa87c1d60a30f605b067b5f92ad8843915de Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:31:26 -0700 Subject: [PATCH 17/57] LoadChatChannels converted to QueryDatabase --- ucs/database.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 155ee986a..3785992de 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -246,32 +246,21 @@ bool Database::LoadChatChannels() { _log(UCS__INIT, "Loading chat channels from the database."); - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!RunQuery(query,MakeAnyLenString(&query, "select `name`,`owner`,`password`, `minstatus` from `chatchannels`"),errbuf,&result)){ - - _log(UCS__ERROR, "Failed to load channels. %s %s", query, errbuf); - safe_delete_array(query); - + const std::string query = "SELECT `name`, `owner`, `password`, `minstatus` FROM `chatchannels`"; + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "Failed to load channels. %s %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - safe_delete_array(query); + for (auto row = results.begin();row != results.end(); ++row) { + std::string channelName = row[0]; + std::string channelOwner = row[1]; + std::string channelPassword = row[2]; - while((row = mysql_fetch_row(result))) { - - std::string ChannelName = row[0]; - std::string ChannelOwner = row[1]; - std::string ChannelPassword = row[2]; - - ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3])); + ChannelList->CreateChannel(channelName, channelOwner, channelPassword, true, atoi(row[3])); } - mysql_free_result(result); - return true; } From 7a507e8d1ec5e2cddb6a028081364bce4d650b63 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:34:27 -0700 Subject: [PATCH 18/57] SetChannelPassword converted to QueryDatabase --- ucs/database.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 3785992de..063ab5e35 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -264,21 +264,16 @@ bool Database::LoadChatChannels() { return true; } -void Database::SetChannelPassword(std::string ChannelName, std::string Password) { +void Database::SetChannelPassword(std::string channelName, std::string password) { - _log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", ChannelName.c_str(), Password.c_str()); + _log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", channelName.c_str(), password.c_str()); - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; + std::string query = StringFormat("UPDATE `chatchannels` SET `password` = '%s' WHERE `name` = '%s'", + password.c_str(), channelName.c_str()); + auto results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__ERROR, "Error updating password in database: %s, %s", query.c_str(), results.ErrorMessage().c_str()); - if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `password`='%s' where `name`='%s'", Password.c_str(), - ChannelName.c_str()), errbuf)) { - - _log(UCS__ERROR, "Error updating password in database: %s, %s", query, errbuf); - - } - - safe_delete_array(query); } void Database::SetChannelOwner(std::string ChannelName, std::string Owner) { From 6e7136ea186e41666df7a2104b5460ac2ef32aec Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:38:57 -0700 Subject: [PATCH 19/57] SetChannelOwner converted to QueryDatabase --- ucs/database.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 063ab5e35..22f1431ae 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -276,21 +276,16 @@ void Database::SetChannelPassword(std::string channelName, std::string password) } -void Database::SetChannelOwner(std::string ChannelName, std::string Owner) { +void Database::SetChannelOwner(std::string channelName, std::string owner) { - _log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", ChannelName.c_str(), Owner.c_str()); + _log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", channelName.c_str(), owner.c_str()); - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; + std::string query = StringFormat("UPDATE `chatchannels` SET `owner` = '%s' WHERE `name` = '%s'", + owner.c_str(), channelName.c_str()); + auto results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__ERROR, "Error updating Owner in database: %s, %s", query.c_str(), results.ErrorMessage().c_str()); - if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `owner`='%s' where `name`='%s'", Owner.c_str(), - ChannelName.c_str()), errbuf)) { - - _log(UCS__ERROR, "Error updating Owner in database: %s, %s", query, errbuf); - - } - - safe_delete_array(query); } void Database::SendHeaders(Client *c) { From 2bdc44dfb2fbe335a2e4d7aed904152ed4b59f03 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:47:59 -0700 Subject: [PATCH 20/57] SendHeaders converted to QueryDatabase --- ucs/database.cpp | 129 ++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 73 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 22f1431ae..b05810f0e 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -288,110 +288,93 @@ void Database::SetChannelOwner(std::string channelName, std::string owner) { } -void Database::SendHeaders(Client *c) { +void Database::SendHeaders(Client *client) { - int UnknownField2 = 25015275; - int UnknownField3 = 1; + int unknownField2 = 25015275; + int unknownField3 = 1; + int characterID = FindCharacter(client->MailBoxName().c_str()); - int CharacterID = FindCharacter(c->MailBoxName().c_str()); - _log(UCS__TRACE, "Sendheaders for %s, CharID is %i", c->MailBoxName().c_str(), CharacterID); - if(CharacterID <= 0) + _log(UCS__TRACE, "Sendheaders for %s, CharID is %i", client->MailBoxName().c_str(), characterID); + + if(characterID <= 0) return; + std::string query = StringFormat("SELECT `msgid`,`timestamp`, `from`, `subject`, `status` " + "FROM `mail` WHERE `charid`=%i", characterID); + auto results = QueryDatabase(query); + if (!results.Success()) + return; - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; + char buffer[100]; - if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`,`timestamp`,`from`,`subject`, `status` from `mail` " - "where `charid`=%i", CharacterID),errbuf,&result)){ + int headerCountPacketLength = 0; - safe_delete_array(query); + sprintf(buffer, "%i", client->GetMailBoxNumber()); + headerCountPacketLength += (strlen(buffer) + 1); - return ; - } + sprintf(buffer, "%i", unknownField2); + headerCountPacketLength += (strlen(buffer) + 1); - safe_delete_array(query); + sprintf(buffer, "%i", unknownField3); + headerCountPacketLength += (strlen(buffer) + 1); - char Buf[100]; + sprintf(buffer, "%i", results.RowCount()); + headerCountPacketLength += (strlen(buffer) + 1); - uint32 NumRows = mysql_num_rows(result); + EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, headerCountPacketLength); - int HeaderCountPacketLength = 0; + char *packetBuffer = (char *)outapp->pBuffer; - sprintf(Buf, "%i", c->GetMailBoxNumber()); - HeaderCountPacketLength += (strlen(Buf) + 1); - - sprintf(Buf, "%i", UnknownField2); - HeaderCountPacketLength += (strlen(Buf) + 1); - - sprintf(Buf, "%i", UnknownField3); - HeaderCountPacketLength += (strlen(Buf) + 1); - - sprintf(Buf, "%i", NumRows); - HeaderCountPacketLength += (strlen(Buf) + 1); - - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, HeaderCountPacketLength); - - char *PacketBuffer = (char *)outapp->pBuffer; - - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber()); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField3); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, NumRows); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber()); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField3); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, results.RowCount()); _pkt(UCS__PACKETS, outapp); - c->QueuePacket(outapp); + client->QueuePacket(outapp); safe_delete(outapp); - int RowNum = 0; + int rowIndex = 0; + for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) { + int headerPacketLength = 0; - while((row = mysql_fetch_row(result))) { + sprintf(buffer, "%i", client->GetMailBoxNumber()); + headerPacketLength += strlen(buffer) + 1; + sprintf(buffer, "%i", unknownField2); + headerPacketLength += strlen(buffer) + 1; + sprintf(buffer, "%i", rowIndex); + headerPacketLength += strlen(buffer) + 1; + headerPacketLength += strlen(row[0]) + 1; + headerPacketLength += strlen(row[1]) + 1; + headerPacketLength += strlen(row[4]) + 1; + headerPacketLength += GetMailPrefix().length() + strlen(row[2]) + 1; + headerPacketLength += strlen(row[3]) + 1; - int HeaderPacketLength = 0; + outapp = new EQApplicationPacket(OP_MailHeader, headerPacketLength); - sprintf(Buf, "%i", c->GetMailBoxNumber()); - HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1; - sprintf(Buf, "%i", UnknownField2); - HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1; - sprintf(Buf, "%i", RowNum); - HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1; + packetBuffer = (char *)outapp->pBuffer; - HeaderPacketLength = HeaderPacketLength + strlen(row[0]) + 1; - HeaderPacketLength = HeaderPacketLength + strlen(row[1]) + 1; - HeaderPacketLength = HeaderPacketLength + strlen(row[4]) + 1; - HeaderPacketLength = HeaderPacketLength + GetMailPrefix().length() + strlen(row[2]) + 1; - HeaderPacketLength = HeaderPacketLength + strlen(row[3]) + 1; - - outapp = new EQApplicationPacket(OP_MailHeader, HeaderPacketLength); - - PacketBuffer = (char *)outapp->pBuffer; - - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber()); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, RowNum); - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[0]); - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[1]); - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[4]); - VARSTRUCT_ENCODE_STRING(PacketBuffer, GetMailPrefix().c_str()); PacketBuffer--; - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]); - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[3]); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber()); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2); + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, rowIndex); + VARSTRUCT_ENCODE_STRING(packetBuffer, row[0]); + VARSTRUCT_ENCODE_STRING(packetBuffer, row[1]); + VARSTRUCT_ENCODE_STRING(packetBuffer, row[4]); + VARSTRUCT_ENCODE_STRING(packetBuffer, GetMailPrefix().c_str()); + packetBuffer--; + VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]); + VARSTRUCT_ENCODE_STRING(packetBuffer, row[3]); _pkt(UCS__PACKETS, outapp); - c->QueuePacket(outapp); + client->QueuePacket(outapp); safe_delete(outapp); - - RowNum++; } - mysql_free_result(result); - } void Database::SendBody(Client *c, int MessageNumber) { From aaf5f8c9307cd99199309ed7d51bf080a939b2c7 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 21:51:40 -0700 Subject: [PATCH 21/57] SendBody converted to QueryDatabase --- ucs/database.cpp | 69 ++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index b05810f0e..b704a271b 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -377,65 +377,52 @@ void Database::SendHeaders(Client *client) { } -void Database::SendBody(Client *c, int MessageNumber) { +void Database::SendBody(Client *client, int messageNumber) { - int CharacterID = FindCharacter(c->MailBoxName().c_str()); + int characterID = FindCharacter(client->MailBoxName().c_str()); - _log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", MessageNumber, c->MailBoxName().c_str(), CharacterID); + _log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", messageNumber, client->MailBoxName().c_str(), characterID); - if(CharacterID <= 0) + if(characterID <= 0) return; - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`, `body`, `to` from `mail` " - "where `charid`=%i and `msgid`=%i", CharacterID, MessageNumber), errbuf, &result)){ - safe_delete_array(query); - - return ; - } - - safe_delete_array(query); - - if (mysql_num_rows(result) != 1) { - - mysql_free_result(result); - + std::string query = StringFormat("SELECT `msgid`, `body`, `to` FROM `mail` " + "WHERE `charid`=%i AND `msgid`=%i", characterID, messageNumber); + auto results = QueryDatabase(query); + if (!results.Success()) return; - } - row = mysql_fetch_row(result); - _log(UCS__TRACE, "Message: %i body (%i bytes)", MessageNumber, strlen(row[1])); + if (results.RowCount() != 1) + return; - int PacketLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]); + auto row = results.begin(); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,PacketLength); + _log(UCS__TRACE, "Message: %i body (%i bytes)", messageNumber, strlen(row[1])); - char *PacketBuffer = (char *)outapp->pBuffer; + int packetLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]); - VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber()); - VARSTRUCT_ENCODE_STRING(PacketBuffer,row[0]); - VARSTRUCT_ENCODE_STRING(PacketBuffer,row[1]); - VARSTRUCT_ENCODE_STRING(PacketBuffer,"1"); - VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a); - VARSTRUCT_ENCODE_STRING(PacketBuffer, "TO:"); PacketBuffer--; - VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]); PacketBuffer--; // Overwrite the null terminator - VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a); + EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,packetLength); - mysql_free_result(result); + char *packetBuffer = (char *)outapp->pBuffer; + + VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber()); + VARSTRUCT_ENCODE_STRING(packetBuffer,row[0]); + VARSTRUCT_ENCODE_STRING(packetBuffer,row[1]); + VARSTRUCT_ENCODE_STRING(packetBuffer,"1"); + VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a); + VARSTRUCT_ENCODE_STRING(packetBuffer, "TO:"); + packetBuffer--; + VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]); + packetBuffer--; // Overwrite the null terminator + VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a); _pkt(UCS__PACKETS, outapp); - c->QueuePacket(outapp); + client->QueuePacket(outapp); safe_delete(outapp); - - } bool Database::SendMail(std::string Recipient, std::string From, std::string Subject, std::string Body, std::string RecipientsString) { From 8529384b009a56214fc8a888374d811b62319f08 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:00:40 -0700 Subject: [PATCH 22/57] SendMail converted to QueryDatabase --- ucs/database.cpp | 78 +++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index b704a271b..6bdf2b1e8 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -425,72 +425,62 @@ void Database::SendBody(Client *client, int messageNumber) { safe_delete(outapp); } -bool Database::SendMail(std::string Recipient, std::string From, std::string Subject, std::string Body, std::string RecipientsString) { +bool Database::SendMail(std::string recipient, std::string from, std::string subject, std::string body, std::string recipientsString) { - int CharacterID; + int characterID; - std::string CharacterName; + std::string characterName; //printf("Database::SendMail(%s, %s, %s)\n", Recipient.c_str(), From.c_str(), Subject.c_str()); - std::string::size_type LastPeriod = Recipient.find_last_of("."); + auto lastPeriod = recipient.find_last_of("."); - if(LastPeriod == std::string::npos) - CharacterName = Recipient; + if(lastPeriod == std::string::npos) + characterName = recipient; else - CharacterName = Recipient.substr(LastPeriod+1); + characterName = recipient.substr(lastPeriod+1); - CharacterName[0] = toupper(CharacterName[0]); + characterName[0] = toupper(characterName[0]); - for(unsigned int i = 1; i < CharacterName.length(); i++) - CharacterName[i] = tolower(CharacterName[i]); + for(unsigned int i = 1; i < characterName.length(); i++) + characterName[i] = tolower(characterName[i]); - CharacterID = FindCharacter(CharacterName.c_str()); + characterID = FindCharacter(characterName.c_str()); - _log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", CharacterName.c_str(), CharacterID); + _log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", characterName.c_str(), characterID); - if(CharacterID <= 0) return false; + if(characterID <= 0) + return false; - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; + char *escSubject = new char[subject.length() * 2 + 1]; + char *escBody = new char[body.length() * 2 + 1]; - char *EscSubject = new char[Subject.length() * 2 + 1]; - char *EscBody = new char[Body.length() * 2 + 1]; + DoEscapeString(escSubject, subject.c_str(), subject.length()); + DoEscapeString(escBody, body.c_str(), body.length()); - DoEscapeString(EscSubject, Subject.c_str(), Subject.length()); - DoEscapeString(EscBody, Body.c_str(), Body.length()); - - const char *MailQuery="INSERT INTO `mail` (`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) " - "VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)"; - - uint32 LastMsgID; - - int Now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like. - - if(!RunQuery(query, MakeAnyLenString(&query, MailQuery, CharacterID, Now, From.c_str(), EscSubject, EscBody, - RecipientsString.c_str(), 1), errbuf, 0, 0, &LastMsgID)) { - - _log(UCS__ERROR, "SendMail: Query %s failed with error %s", query, errbuf); - - safe_delete_array(EscSubject); - safe_delete_array(EscBody); - safe_delete_array(query); + int now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like. + std::string query = StringFormat("INSERT INTO `mail` " + "(`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) " + "VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)", + characterID, now, from.c_str(), escSubject, escBody, + recipientsString.c_str(), 1); + safe_delete_array(escSubject); + safe_delete_array(escBody); + auto results = QueryDatabase(query); + if(!results.Success()) { + _log(UCS__ERROR, "SendMail: Query %s failed with error %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - _log(UCS__TRACE, "MessageID %i generated, from %s, to %s", LastMsgID, From.c_str(), Recipient.c_str()); + _log(UCS__TRACE, "MessageID %i generated, from %s, to %s", results.LastInsertedID(), from.c_str(), recipient.c_str()); - safe_delete_array(EscSubject); - safe_delete_array(EscBody); - safe_delete_array(query); - Client *c = CL->IsCharacterOnline(CharacterName); + Client *client = CL->IsCharacterOnline(characterName); - if(c) { - std::string FQN = GetMailPrefix() + From; - - c->SendNotification(c->GetMailBoxNumber(CharacterName), Subject, FQN, LastMsgID); + if(client) { + std::string FQN = GetMailPrefix() + from; + client->SendNotification(client->GetMailBoxNumber(characterName), subject, FQN, results.LastInsertedID()); } MailMessagesSent++; From c9bd662b57cfb01d62b8070ac4cd5b6aac6373f6 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:07:04 -0700 Subject: [PATCH 23/57] SetMessageStatus converted to QueryDatabase --- ucs/database.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 6bdf2b1e8..4e47b27ed 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -428,11 +428,8 @@ void Database::SendBody(Client *client, int messageNumber) { bool Database::SendMail(std::string recipient, std::string from, std::string subject, std::string body, std::string recipientsString) { int characterID; - std::string characterName; - //printf("Database::SendMail(%s, %s, %s)\n", Recipient.c_str(), From.c_str(), Subject.c_str()); - auto lastPeriod = recipient.find_last_of("."); if(lastPeriod == std::string::npos) @@ -488,22 +485,21 @@ bool Database::SendMail(std::string recipient, std::string from, std::string sub return true; } -void Database::SetMessageStatus(int MessageNumber, int Status) { +void Database::SetMessageStatus(int messageNumber, int status) { - _log(UCS__TRACE, "SetMessageStatus %i %i", MessageNumber, Status); + _log(UCS__TRACE, "SetMessageStatus %i %i", messageNumber, status); - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; + if(status == 0) { + std::string query = StringFormat("DELETE FROM `mail` WHERE `msgid` = %i", messageNumber); + auto results = QueryDatabase(query); + return; + } - if(Status == 0) - RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `msgid`=%i", MessageNumber), errbuf); - else if (!RunQuery(query, MakeAnyLenString(&query, "update `mail` set `status`=%i where `msgid`=%i", Status, MessageNumber), errbuf)) { + std::string query = StringFormat("UPDATE `mail` SET `status` = %i WHERE `msgid`=%i", status, messageNumber); + auto results = QueryDatabase(query); + if (!results.Success()) + _log(UCS__ERROR, "Error updating status %s, %s", query.c_str(), results.ErrorMessage().c_str()); - _log(UCS__ERROR, "Error updating status %s, %s", query, errbuf); - - } - - safe_delete_array(query); } void Database::ExpireMail() { From 20e978b6769f6096775fac3bdcff9e2a56356d4a Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:16:37 -0700 Subject: [PATCH 24/57] ExpiredMail converted to QueryDatabase --- ucs/database.cpp | 68 +++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 4e47b27ed..d66b41418 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -506,58 +506,48 @@ void Database::ExpireMail() { _log(UCS__INIT, "Expiring mail..."); - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - uint32 AffectedRows; - - if (!RunQuery(query,MakeAnyLenString(&query, "select COUNT(*) from `mail` "),errbuf,&result)){ - _log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf); - safe_delete_array(query); - return ; + std::string query = "SELECT COUNT(*) FROM `mail`"; + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str()); + return; } - safe_delete_array(query); - row = mysql_fetch_row(result); + auto row = results.begin(); _log(UCS__INIT, "There are %s messages in the database.", row[0]); - mysql_free_result(result); - // Expire Trash if(RuleI(Mail, ExpireTrash) >= 0) { - if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=4 and `timestamp` < %i", - time(nullptr) - RuleI(Mail, ExpireTrash)), errbuf, 0, &AffectedRows)) { - _log(UCS__INIT, "Expired %i trash messages.", AffectedRows); - } - else { - _log(UCS__ERROR, "Error expiring trash messages, %s %s", query, errbuf); - } - safe_delete_array(query); + query = StringFormat("DELETE FROM `mail` WHERE `status`=4 AND `timestamp` < %i", + time(nullptr) - RuleI(Mail, ExpireTrash)); + results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected()); + else + _log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str()); } + // Expire Read if(RuleI(Mail, ExpireRead) >= 0) { - if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=3 and `timestamp` < %i", - time(nullptr) - RuleI(Mail, ExpireRead)), errbuf, 0, &AffectedRows)) { - _log(UCS__INIT, "Expired %i read messages.", AffectedRows); - } - else { - _log(UCS__ERROR, "Error expiring read messages, %s %s", query, errbuf); - } - safe_delete_array(query); + query = StringFormat("DELETE FROM `mail` WHERE `status` = 3 AND `timestamp` < %i", + time(nullptr) - RuleI(Mail, ExpireRead)); + results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__INIT, "Expired %i read messages.", results.RowsAffected()); + else + _log(UCS__ERROR, "Error expiring read messages, %s %s", query.c_str(), results.ErrorMessage().c_str()); } + // Expire Unread if(RuleI(Mail, ExpireUnread) >= 0) { - if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=1 and `timestamp` < %i", - time(nullptr) - RuleI(Mail, ExpireUnread)), errbuf, 0, &AffectedRows)) { - _log(UCS__INIT, "Expired %i unread messages.", AffectedRows); - } - else { - _log(UCS__ERROR, "Error expiring unread messages, %s %s", query, errbuf); - } - safe_delete_array(query); + query = StringFormat("DELETE FROM `mail` WHERE `status`=1 AND `timestamp` < %i", + time(nullptr) - RuleI(Mail, ExpireUnread)); + results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__INIT, "Expired %i unread messages.", results.RowsAffected()); + else + _log(UCS__ERROR, "Error expiring unread messages, %s %s", query.c_str(), results.ErrorMessage().c_str()); } } From 9d5f427f5738d1e17538a8e9cd28c98f5e01f8b9 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:20:16 -0700 Subject: [PATCH 25/57] AddFriendOrIgnore converted to QueryDatabase --- ucs/database.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index d66b41418..36e2b1251 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -551,22 +551,17 @@ void Database::ExpireMail() { } } -void Database::AddFriendOrIgnore(int CharID, int Type, std::string Name) { +void Database::AddFriendOrIgnore(int charID, int type, std::string name) { - const char *FriendsQuery="INSERT INTO `friends` (`charid`, `type`, `name`) VALUES ('%i', %i, '%s')"; - - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - - - if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0)) - _log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query, errbuf); + std::string query = StringFormat("INSERT INTO `friends` (`charid`, `type`, `name`) " + "VALUES('%i', %i, '%s')", + charID, type, CapitaliseName(name).c_str()); + auto results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query.c_str(), results.ErrorMessage().c_str()); else - _log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.", - CharID, Type, Name.c_str()); + _log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.", charID, type, name.c_str()); - - safe_delete_array(query); } void Database::RemoveFriendOrIgnore(int CharID, int Type, std::string Name) { From c1469a3a8e1a4f592aa70bd1ef9e380153d5289e Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:22:49 -0700 Subject: [PATCH 26/57] RemoveFriendOrIgnore converted to QueryDatabase --- ucs/database.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 36e2b1251..880972152 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -564,21 +564,17 @@ void Database::AddFriendOrIgnore(int charID, int type, std::string name) { } -void Database::RemoveFriendOrIgnore(int CharID, int Type, std::string Name) { +void Database::RemoveFriendOrIgnore(int charID, int type, std::string name) { - const char *FriendsQuery="DELETE FROM `friends` WHERE `charid`=%i AND `type`=%i and `name`='%s'"; - - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - - if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0)) - _log(UCS__ERROR, "Error removing friend/ignore, query was %s", query); + std::string query = StringFormat("DELETE FROM `friends` WHERE `charid` = %i " + "AND `type` = %i AND `name` = '%s'", + charID, type, CapitaliseName(name).c_str()); + auto results = QueryDatabase(query); + if(!results.Success()) + _log(UCS__ERROR, "Error removing friend/ignore, query was %s", query.c_str()); else - _log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.", - CharID, Type, Name.c_str()); + _log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.", charID, type, name.c_str()); - - safe_delete_array(query); } void Database::GetFriendsAndIgnore(int CharID, std::vector &Friends, std::vector &Ignorees) { From 232d61b98394cbe9a46babc22b14b2747cd64c85 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 23 Aug 2014 22:33:05 -0700 Subject: [PATCH 27/57] GetFriendAndIgnore converted to QueryDatabase --- ucs/database.cpp | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index 880972152..d3c44174c 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -577,44 +577,29 @@ void Database::RemoveFriendOrIgnore(int charID, int type, std::string name) { } -void Database::GetFriendsAndIgnore(int CharID, std::vector &Friends, std::vector &Ignorees) { +void Database::GetFriendsAndIgnore(int charID, std::vector &friends, std::vector &ignorees) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - const char *FriendsQuery="select `type`, `name` from `friends` WHERE `charid`=%i"; - - if (!RunQuery(query,MakeAnyLenString(&query, FriendsQuery, CharID),errbuf,&result)){ - - _log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query, errbuf); - - safe_delete_array(query); - - return ; + std::string query = StringFormat("select `type`, `name` FROM `friends` WHERE `charid`=%i", charID); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query.c_str(), results.ErrorMessage().c_str()); + return; } - safe_delete_array(query); - while((row = mysql_fetch_row(result))) { - - std::string Name = row[1]; + for (auto row = results.begin(); row != results.end(); ++row) { + std::string name = row[1]; if(atoi(row[0]) == 0) { - Ignorees.push_back(Name); - _log(UCS__TRACE, "Added Ignoree from DB %s", Name.c_str()); - } - else - { - Friends.push_back(Name); - _log(UCS__TRACE, "Added Friend from DB %s", Name.c_str()); + ignorees.push_back(name); + _log(UCS__TRACE, "Added Ignoree from DB %s", name.c_str()); + continue; } + + friends.push_back(name); + _log(UCS__TRACE, "Added Friend from DB %s", name.c_str()); } - mysql_free_result(result); - - return; } From 377c6a87a2bb629462431cf68c2ab84c1b8b7f71 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 11:53:28 -0700 Subject: [PATCH 28/57] GetDoorsCount converted to QueryDatabase --- zone/doors.cpp | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/zone/doors.cpp b/zone/doors.cpp index c353ce568..d3b9ec6ec 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -568,36 +568,31 @@ void Doors::DumpDoor(){ } int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - query = new char[256]; - sprintf(query, "SELECT MAX(id), count(*) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version); - if (RunQuery(query, strlen(query), errbuf, &result)) { - safe_delete_array(query); - row = mysql_fetch_row(result); - if (row != nullptr && row[1] != 0) { - int32 ret = atoi(row[1]); - if (oMaxID) { - if (row[0]) - *oMaxID = atoi(row[0]); - else - *oMaxID = 0; - } - mysql_free_result(result); - return ret; - } - mysql_free_result(result); - } - else { - std::cerr << "Error in GetDoorsCount query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); + std::string query = StringFormat("SELECT MAX(id), count(*) FROM doors " + "WHERE zone = '%s' AND (version = %u OR version = -1)", + zone_name, version); + auto results = QueryDatabase(query); + if (!results.Success()) { + std::cerr << "Error in GetDoorsCount query '" << query << "' " << results.ErrorMessage() << std::endl; return -1; - } + } + + if (results.RowCount() != 1) + return -1; + + auto row = results.begin(); + + if (!oMaxID) + return atoi(row[1]); + + if (row[0]) + *oMaxID = atoi(row[0]); + else + *oMaxID = 0; + + return atoi(row[1]); - return -1; } int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) { From 8f4e2e99db454a124a6ccaf9b31a476fbce41d21 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:00:45 -0700 Subject: [PATCH 29/57] GetDoorsCountPlusOne converted to QueryDatabase --- zone/doors.cpp | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/zone/doors.cpp b/zone/doors.cpp index d3b9ec6ec..375b59be5 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -596,34 +596,24 @@ int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 v } int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - uint32 oMaxID = 0; - MYSQL_RES *result; - MYSQL_ROW row; - query = new char[256]; - sprintf(query, "SELECT MAX(id) FROM doors WHERE zone='%s' AND version=%u", zone_name, version); - if (RunQuery(query, strlen(query), errbuf, &result)) { - safe_delete_array(query); - row = mysql_fetch_row(result); - if (row != nullptr && row[1] != 0) { - if (row[0]) - oMaxID = atoi(row[0]) + 1; - else - oMaxID = 0; - mysql_free_result(result); - return oMaxID; - } - mysql_free_result(result); - } - else { - std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); + std::string query = StringFormat("SELECT MAX(id) FROM doors " + "WHERE zone = '%s' AND version = %u", zone_name, version); + auto results = QueryDatabase(query); + if (!results.Success()) { + std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl; return -1; - } + } - return -1; + if (results.RowCount() != 1) + return -1; + + auto row = results.begin(); + + if (!row[0]) + return 0; + + return atoi(row[0]) + 1; } int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) { From 5d6d48988964f46063dfb786c345ae1ccbe4b944 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:08:39 -0700 Subject: [PATCH 30/57] GetDoorsDBCountPlusOne converted to QueryDatabase --- zone/doors.cpp | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/zone/doors.cpp b/zone/doors.cpp index 375b59be5..f01c4dbc0 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -617,34 +617,27 @@ int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) { } int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; + uint32 oMaxID = 0; - MYSQL_RES *result; - MYSQL_ROW row; - query = new char[256]; - sprintf(query, "SELECT MAX(doorid) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version); - if (RunQuery(query, strlen(query), errbuf, &result)) { - safe_delete_array(query); - row = mysql_fetch_row(result); - if (row != nullptr && row[1] != 0) { - if (row[0]) - oMaxID = atoi(row[0]) + 1; - else - oMaxID = 0; - mysql_free_result(result); - return oMaxID; - } - mysql_free_result(result); - } - else { - std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); + std::string query = StringFormat("SELECT MAX(doorid) FROM doors " + "WHERE zone = '%s' AND (version = %u OR version = -1)", + zone_name, version); + auto results = QueryDatabase(query); + if (!results.Success()) { + std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl; return -1; } - return -1; + if (results.RowCount() != 1) + return -1; + + auto row = results.begin(); + + if (!row[0]) + return 0; + + return atoi(row[0]) + 1; } bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) { From 9707b53df26b68a3938c43bca7bd17d3ee5de51c Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:14:16 -0700 Subject: [PATCH 31/57] LoadDoors converted to QueryDatabase --- zone/doors.cpp | 104 +++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/zone/doors.cpp b/zone/doors.cpp index f01c4dbc0..5ff7eae26 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -642,61 +642,63 @@ int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) { LogFile->write(EQEMuLog::Status, "Loading Doors from database..."); - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; + // Door tmpDoor; - MakeAnyLenString(&query, "SELECT id,doorid,zone,name,pos_x,pos_y,pos_z,heading," - "opentype,guild,lockpick,keyitem,nokeyring,triggerdoor,triggertype,dest_zone,dest_instance,dest_x," - "dest_y,dest_z,dest_heading,door_param,invert_state,incline,size,is_ldon_door,client_version_mask " - "FROM doors WHERE zone='%s' AND (version=%u OR version=-1) ORDER BY doorid asc", zone_name, version); - if (RunQuery(query, strlen(query), errbuf, &result)) { - safe_delete_array(query); - int32 r; - for(r = 0; (row = mysql_fetch_row(result)); r++) { - if(r >= iDoorCount) { - std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl; - break; - } - memset(&into[r], 0, sizeof(Door)); - into[r].db_id = atoi(row[0]); - into[r].door_id = atoi(row[1]); - strn0cpy(into[r].zone_name,row[2],32); - strn0cpy(into[r].door_name,row[3],32); - into[r].pos_x = (float)atof(row[4]); - into[r].pos_y = (float)atof(row[5]); - into[r].pos_z = (float)atof(row[6]); - into[r].heading = (float)atof(row[7]); - into[r].opentype = atoi(row[8]); - into[r].guild_id = atoi(row[9]); - into[r].lockpick = atoi(row[10]); - into[r].keyitem = atoi(row[11]); - into[r].nokeyring = atoi(row[12]); - into[r].trigger_door = atoi(row[13]); - into[r].trigger_type = atoi(row[14]); - strn0cpy(into[r].dest_zone, row[15], 32); - into[r].dest_instance_id = atoi(row[16]); - into[r].dest_x = (float) atof(row[17]); - into[r].dest_y = (float) atof(row[18]); - into[r].dest_z = (float) atof(row[19]); - into[r].dest_heading = (float) atof(row[20]); - into[r].door_param=atoi(row[21]); - into[r].invert_state=atoi(row[22]); - into[r].incline=atoi(row[23]); - into[r].size=atoi(row[24]); - into[r].is_ldon_door=atoi(row[25]); - into[r].client_version_mask = (uint32)strtoul(row[26], nullptr, 10); - } - mysql_free_result(result); - } - else - { - std::cerr << "Error in DBLoadDoors query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); + std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, " + "opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, " + "dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, " + "door_param, invert_state, incline, size, is_ldon_door, client_version_mask " + "FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) " + "ORDER BY doorid asc", zone_name, version); + auto results = QueryDatabase(query); + if (!results.Success()){ + std::cerr << "Error in DBLoadDoors query '" << query << "' " << results.ErrorMessage() << std::endl; return false; } + + int32 rowIndex = 0; + for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) { + if(rowIndex >= iDoorCount) { + std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl; + break; + } + + memset(&into[rowIndex], 0, sizeof(Door)); + + into[rowIndex].db_id = atoi(row[0]); + into[rowIndex].door_id = atoi(row[1]); + + strn0cpy(into[rowIndex].zone_name,row[2],32); + strn0cpy(into[rowIndex].door_name,row[3],32); + + into[rowIndex].pos_x = (float)atof(row[4]); + into[rowIndex].pos_y = (float)atof(row[5]); + into[rowIndex].pos_z = (float)atof(row[6]); + into[rowIndex].heading = (float)atof(row[7]); + into[rowIndex].opentype = atoi(row[8]); + into[rowIndex].guild_id = atoi(row[9]); + into[rowIndex].lockpick = atoi(row[10]); + into[rowIndex].keyitem = atoi(row[11]); + into[rowIndex].nokeyring = atoi(row[12]); + into[rowIndex].trigger_door = atoi(row[13]); + into[rowIndex].trigger_type = atoi(row[14]); + + strn0cpy(into[rowIndex].dest_zone, row[15], 32); + + into[rowIndex].dest_instance_id = atoi(row[16]); + into[rowIndex].dest_x = (float) atof(row[17]); + into[rowIndex].dest_y = (float) atof(row[18]); + into[rowIndex].dest_z = (float) atof(row[19]); + into[rowIndex].dest_heading = (float) atof(row[20]); + into[rowIndex].door_param=atoi(row[21]); + into[rowIndex].invert_state=atoi(row[22]); + into[rowIndex].incline=atoi(row[23]); + into[rowIndex].size=atoi(row[24]); + into[rowIndex].is_ldon_door=atoi(row[25]); + into[rowIndex].client_version_mask = (uint32)strtoul(row[26], nullptr, 10); + } + return true; } From 3d1521857ea7a1077a8c3b45265d874014f3a1d6 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:21:16 -0700 Subject: [PATCH 32/57] LoadStaticZonePoints converted to QueryDatabase --- zone/zone.cpp | 66 ++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/zone/zone.cpp b/zone/zone.cpp index a3026425c..a85b2d9ff 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1678,45 +1678,41 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien bool ZoneDatabase::LoadStaticZonePoints(LinkedList* zone_point_list, const char* zonename, uint32 version) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; + zone_point_list->Clear(); zone->numzonepoints = 0; - MakeAnyLenString(&query, "SELECT x, y, z, target_x, target_y, " - "target_z, target_zone_id, heading, target_heading, number, " - "target_instance, client_version_mask FROM zone_points " - "WHERE zone='%s' AND (version=%i OR version=-1) order by number", zonename, version); - if (RunQuery(query, strlen(query), errbuf, &result)) - { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) - { - ZonePoint* zp = new ZonePoint; - zp->x = atof(row[0]); - zp->y = atof(row[1]); - zp->z = atof(row[2]); - zp->target_x = atof(row[3]); - zp->target_y = atof(row[4]); - zp->target_z = atof(row[5]); - zp->target_zone_id = atoi(row[6]); - zp->heading = atof(row[7]); - zp->target_heading = atof(row[8]); - zp->number = atoi(row[9]); - zp->target_zone_instance = atoi(row[10]); - zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0); - zone_point_list->Insert(zp); - zone->numzonepoints++; - } - mysql_free_result(result); - } - else - { - std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); + std::string query = StringFormat("SELECT x, y, z, target_x, target_y, " + "target_z, target_zone_id, heading, target_heading, " + "number, target_instance, client_version_mask " + "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) " + "ORDER BY number", zonename, version); + auto results = QueryDatabase(query); + if (!results.Success()) { + std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << results.ErrorMessage() << std::endl; return false; } + + for (auto row = results.begin(); row != results.end(); ++row) { + ZonePoint* zp = new ZonePoint; + + zp->x = atof(row[0]); + zp->y = atof(row[1]); + zp->z = atof(row[2]); + zp->target_x = atof(row[3]); + zp->target_y = atof(row[4]); + zp->target_z = atof(row[5]); + zp->target_zone_id = atoi(row[6]); + zp->heading = atof(row[7]); + zp->target_heading = atof(row[8]); + zp->number = atoi(row[9]); + zp->target_zone_instance = atoi(row[10]); + zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0); + + zone_point_list->Insert(zp); + + zone->numzonepoints++; + } + return true; } From e7ef4b5484fe3df0fa0e78eff5ac415aa7ddf7ea Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:37:44 -0700 Subject: [PATCH 33/57] SpellGlobalCheck converted to QueryDatabase --- zone/spells.cpp | 160 ++++++++++++++++++++++-------------------------- 1 file changed, 74 insertions(+), 86 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 4eddf5883..357fafbd4 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1252,7 +1252,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } - if(IsClient()) { + if(IsClient()) { CheckNumHitsRemaining(NUMHIT_MatchingSpells); TrySympatheticProc(target, spell_id); } @@ -1378,7 +1378,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id); targetType = ST_GroupClientAndPet; } - + if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){ Message_StringID(13,SPELL_NEED_TAR); return false; @@ -1386,16 +1386,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce //Must be out of combat. (If Beneficial checks casters combat state, Deterimental checks targets) if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat){ - if (IsDetrimentalSpell(spell_id)) { - if ( (spell_target->IsNPC() && spell_target->IsEngaged()) || + if (IsDetrimentalSpell(spell_id)) { + if ( (spell_target->IsNPC() && spell_target->IsEngaged()) || (spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount())){ Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string return false; } } - else if (IsBeneficialSpell(spell_id)) { - if ( (IsNPC() && IsEngaged()) || + else if (IsBeneficialSpell(spell_id)) { + if ( (IsNPC() && IsEngaged()) || (IsClient() && CastToClient()->GetAggroCount())){ if (IsDiscipline(spell_id)) Message_StringID(13,NO_ABILITY_IN_COMBAT); @@ -1409,16 +1409,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce //Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets) else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat){ - if (IsDetrimentalSpell(spell_id)) { - if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) || + if (IsDetrimentalSpell(spell_id)) { + if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) || (spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount())){ Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string return false; } } - else if (IsBeneficialSpell(spell_id)) { - if ( (IsNPC() && !IsEngaged()) || + else if (IsBeneficialSpell(spell_id)) { + if ( (IsNPC() && !IsEngaged()) || (IsClient() && !CastToClient()->GetAggroCount())){ if (IsDiscipline(spell_id)) Message_StringID(13,NO_ABILITY_OUT_OF_COMBAT); @@ -1782,10 +1782,10 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce case ST_PetMaster: { - + Mob *owner = nullptr; - - if (IsPet()) + + if (IsPet()) owner = GetOwner(); else if ((IsNPC() && CastToNPC()->GetSwarmOwner())) owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); @@ -1975,7 +1975,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 if (!TrySpellProjectile(spell_target, spell_id)) return false; } - + else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) { if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) { // Prevent mana usage/timers being set for beneficial buffs @@ -2723,7 +2723,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker))) return -1; } - + if (spellbonuses.DStacker[0]) { if ((effect2 == SE_DStacker) && (sp2.effectid[i] <= spellbonuses.DStacker[1])) return -1; @@ -2775,7 +2775,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d, but we do not have that effect on that slot. Ignored.", sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value); } - } + } } } else { mlog(SPELLS__STACKING, "%s (%d) and %s (%d) appear to be in the same line, skipping Stacking Overwrite/Blocking checks", @@ -3564,7 +3564,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r if(spell_effectiveness == 0 || !IsPartialCapableSpell(spell_id) ) { mlog(SPELLS__RESISTS, "Spell %d was completely resisted by %s", spell_id, spelltar->GetName()); - + if (spells[spell_id].resisttype == RESIST_PHYSICAL){ Message_StringID(MT_SpellFailure, PHYSICAL_RESIST_FAIL,spells[spell_id].name); spelltar->Message_StringID(MT_SpellFailure, YOU_RESIST, spells[spell_id].name); @@ -3707,7 +3707,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r TrySpellTrigger(spelltar, spell_id); TryApplyEffect(spelltar, spell_id); - + if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) { int32 aggro_amount = CheckAggroAmount(spell_id, isproc); mlog(SPELLS__CASTING, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount); @@ -3733,7 +3733,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r safe_delete(action_packet); return false; } - + // cause the effects to the target if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness)) { @@ -3746,11 +3746,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r return false; } - + if (IsDetrimentalSpell(spell_id)) { - + CheckNumHitsRemaining(NUMHIT_OutgoingSpells); - + if (spelltar) spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells); } @@ -4408,7 +4408,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if (CharismaCheck) { - /* + /* Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 255 CHA (min ~ 75 cha) Charisma less than ~ 75 gives a postive modifier to resist checks at approximate ratio of -10 CHA = +6 Resist. Mez spells do same initial resist check as a above. @@ -4470,7 +4470,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if (CharmTick) { int min_charmbreakchance = ((100/RuleI(Spells, CharmBreakCheckChance))/66 * 100)*2; - + if (resist_chance < min_charmbreakchance) resist_chance = min_charmbreakchance; } @@ -4965,68 +4965,56 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) { return -1; //default } -bool Client::SpellGlobalCheck(uint16 Spell_ID, uint16 Char_ID) { +bool Client::SpellGlobalCheck(uint16 spell_ID, uint16 char_ID) { - std::string Spell_Global_Name; - int Spell_Global_Value; - int Global_Value; + std::string spell_Global_Name; + int spell_Global_Value; + int global_Value; - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - - if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT qglobal, value FROM spell_globals WHERE spellid=%i", Spell_ID), errbuf, &result)) { - safe_delete_array(query); - - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - Spell_Global_Name = row[0]; - Spell_Global_Value = atoi(row[1]); - - mysql_free_result(result); - - if (Spell_Global_Name.empty()) { // If the entry in the spell_globals table has nothing set for the qglobal name - return true; - } - else if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT value FROM quest_globals WHERE charid=%i AND name='%s'", Char_ID, Spell_Global_Name.c_str()), errbuf, &result)) { - safe_delete_array(query); - - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - - Global_Value = atoi(row[0]); - mysql_free_result(result); - if (Global_Value == Spell_Global_Value) { // If the values match from both tables, allow the spell to be scribed - return true; - } - else if (Global_Value > Spell_Global_Value) { // Check if the qglobal value is greater than the require spellglobal value - return true; - } - else // If no matching result found in qglobals, don't scribe this spell - { - LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_Global_Value, Global_Value, Spell_ID); - return false; - } - } - else - LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_ID); - safe_delete_array(query); - } - else - LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", Spell_ID, Spell_Global_Name.c_str(), Spell_Global_Value); - } - else { - return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing - } - mysql_free_result(result); - } - else { - LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", Spell_ID, query, errbuf); - safe_delete_array(query); + std::string query = StringFormat("SELECT qglobal, value FROM spell_globals " + "WHERE spellid = %i", spell_ID); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", spell_ID, query.c_str(), results.ErrorMessage().c_str()); return false; // Query failed, so prevent spell from scribing just in case - } - return false; // Default is false + } + + if (results.RowCount() != 1) + return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing + + auto row = results.begin(); + spell_Global_Name = row[0]; + spell_Global_Value = atoi(row[1]); + + if (spell_Global_Name.empty()) + return true; // If the entry in the spell_globals table has nothing set for the qglobal name + + query = StringFormat("SELECT value FROM quest_globals " + "WHERE charid = %i AND name = '%s'", + char_ID, spell_Global_Name.c_str()); + results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value); + return false; + } + + if (results.RowCount() != 1) { + LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID); + return false; + } + + row = results.begin(); + + global_Value = atoi(row[0]); + + if (global_Value == spell_Global_Value) + return true; // If the values match from both tables, allow the spell to be scribed + else if (global_Value > spell_Global_Value) + return true; // Check if the qglobal value is greater than the require spellglobal value + + // If no matching result found in qglobals, don't scribe this spell + LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID); + return false; } // TODO get rid of this @@ -5081,7 +5069,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) { } bool Mob::IsCombatProc(uint16 spell_id) { - + if (RuleB(Spells, FocusCombatProcs)) return false; @@ -5092,7 +5080,7 @@ bool Mob::IsCombatProc(uint16 spell_id) { { for (int i = 0; i < MAX_PROCS; i++){ - if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id + if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id || RangedProcs[i].spellID == spell_id){ return true; } @@ -5150,7 +5138,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id { if(spell_id == SPELL_UNKNOWN) return(false); - + int i; for (i = 0; i < MAX_PROCS; i++) { if (DefensiveProcs[i].spellID == SPELL_UNKNOWN) { From adf36bf912d10440cde2d928e71939dab03c0a4d Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:46:02 -0700 Subject: [PATCH 34/57] LoadSpawnGroups converted to QueryDatabase --- zone/spawngroup.cpp | 82 +++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index fc0360aee..ef0a0882a 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -140,53 +140,49 @@ bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) { } bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - query = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result)) - { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) { - SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); - } - mysql_free_result(result); - } - else - { - _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query); - safe_delete_array(query); + std::string query = StringFormat("SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, " + "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " + "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " + "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " + "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID " + "AND spawn2.version = %u and zone = '%s'", version, zone_name); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query.c_str()); return false; - } + } - query = 0; - if (RunQuery(query, MakeAnyLenString(&query, - "SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, " - "npc_types.spawn_limit AS sl " - "FROM spawnentry, spawn2, npc_types " - "WHERE spawnentry.npcID=npc_types.id AND spawnentry.spawngroupID=spawn2.spawngroupID " - "AND zone='%s'", zone_name), errbuf, &result)) { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) - { - SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); - if (sg) - sg->AddSpawnEntry(newSpawnEntry); - else - _log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query); - } - mysql_free_result(result); - } - else - { - _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query); - safe_delete_array(query); + for (auto row = results.begin(); row != results.end(); ++row) { + SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), + atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), + atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); + spawn_group_list->AddSpawnGroup(newSpawnGroup); + } + + query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, " + "npc_types.spawn_limit AS sl " + "FROM spawnentry, spawn2, npc_types " + "WHERE spawnentry.npcID=npc_types.id " + "AND spawnentry.spawngroupID = spawn2.spawngroupID " + "AND zone = '%s'", zone_name); + results = QueryDatabase(query); + if (!results.Success()) { + _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query.c_str()); return false; - } + } + + for (auto row = results.begin(); row != results.end(); ++row) { + SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); + SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); + + if (!sg) { + _log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query.c_str()); + continue; + } + + sg->AddSpawnEntry(newSpawnEntry); + } return true; } From 932dd836d0f706d6de579919fc49bb34a4675cb2 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 12:54:06 -0700 Subject: [PATCH 35/57] LoadSpawnGroupsByID converted to QueryDatabase --- zone/spawngroup.cpp | 73 +++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index ef0a0882a..81d6c5d51 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -188,49 +188,44 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG } bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - query = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result)) - { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) { - SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); - } - mysql_free_result(result); - } - else - { - _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query); - safe_delete_array(query); + + std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, " + "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " + "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " + "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " + "FROM spawngroup WHERE spawngroup.ID = '%i'", spawngroupid); + auto results = QueryDatabase(query); + if (!results.Success()) { + _log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query.c_str()); + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); + spawn_group_list->AddSpawnGroup(newSpawnGroup); + } + + query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, " + "spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup " + "WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' " + "ORDER BY chance", spawngroupid); + results = QueryDatabase(query); + if (!results.Success()) { + _log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", query.c_str()); return false; } - query = 0; - if (RunQuery(query, MakeAnyLenString(&query, - "SELECT DISTINCT spawnentry.spawngroupID, spawnentry.npcid, spawnentry.chance, spawngroup.spawn_limit FROM spawnentry,spawngroup WHERE spawnentry.spawngroupID='%i' AND spawngroup.spawn_limit='0' ORDER by chance", spawngroupid), errbuf, &result)) { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) - { - SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); - if (sg) - sg->AddSpawnEntry(newSpawnEntry); - else - _log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]); - } - mysql_free_result(result); - } - else - { - _log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", row[0]); - safe_delete_array(query); - return false; - } + for(auto row = results.begin(); row != results.end(); ++row) { + SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); + SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); + if (!sg) { + _log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]); + continue; + } + + sg->AddSpawnEntry(newSpawnEntry); + } return true; } From 42a51eb37341cdec85275526bff8eca5d8f31311 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:00:39 -0700 Subject: [PATCH 36/57] PopulateZoneSpawnList converted to QueryDatabase --- zone/spawn2.cpp | 58 +++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index dd541e0a2..53656489c 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -354,34 +354,30 @@ void Spawn2::DeathReset(bool realdeath) } bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; const char *zone_name = database.GetZoneName(zoneid); - - MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE zone='%s' AND version=%u", zone_name, version); - if (RunQuery(query, strlen(query), errbuf, &result)) - { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) - { - Spawn2* newSpawn = 0; - - bool perl_enabled = atoi(row[11]) == 1 ? true : false; - uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000); - newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); - spawn2_list.Insert( newSpawn ); - } - mysql_free_result(result); - } - else - { - LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query, errbuf); - safe_delete_array(query); + std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, " + "respawntime, variance, pathgrid, _condition, " + "cond_value, enabled, animation FROM spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, version); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return false; - } + } + + for (auto row = results.begin(); row != results.end(); ++row) { + Spawn2* newSpawn = 0; + + bool perl_enabled = atoi(row[11]) == 1? true: false; + uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000); + newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), + atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), + atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); + + spawn2_list.Insert(newSpawn); + } return true; } @@ -863,10 +859,10 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in SpawnEvent &cevent = *cur; bool StrictCheck = false; - if(cevent.strict && - cevent.next.hour == tod.hour && - cevent.next.day == tod.day && - cevent.next.month == tod.month && + if(cevent.strict && + cevent.next.hour == tod.hour && + cevent.next.day == tod.day && + cevent.next.month == tod.month && cevent.next.year == tod.year) StrictCheck = true; @@ -894,7 +890,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in //execute the event if(!cevent.strict || StrictCheck) ExecEvent(cevent, false); - + //add the period of the event to the trigger time EQTime::AddMinutes(cevent.period, &cevent.next); ran = true; @@ -926,7 +922,7 @@ void SpawnConditionManager::FindNearestEvent() { if(cevent.enabled) { //see if this event is before our last nearest - if(EQTime::IsTimeBefore(&next_event, &cevent.next)) + if(EQTime::IsTimeBefore(&next_event, &cevent.next)) { memcpy(&next_event, &cevent.next, sizeof(next_event)); next_id = cevent.id; From 9980dfe80e8ac3682ed803bd04400e60c0ef66c7 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:03:45 -0700 Subject: [PATCH 37/57] LoadSpawn2 converted to QueryDatabase --- zone/spawn2.cpp | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 53656489c..e7e5e9e81 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -384,28 +384,33 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spa Spawn2* ZoneDatabase::LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE id=%i", spawn2id), errbuf, &result)) { - if (mysql_num_rows(result) == 1) - { - row = mysql_fetch_row(result); - bool perl_enabled = atoi(row[11]) == 1 ? true : false; - Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); - spawn2_list.Insert( newSpawn ); - mysql_free_result(result); - safe_delete_array(query); - return newSpawn; - } - mysql_free_result(result); - } + std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, " + "respawntime, variance, pathgrid, _condition, " + "cond_value, enabled, animation FROM spawn2 " + "WHERE id = %i", spawn2id); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return nullptr; + } - LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query, errbuf); - safe_delete_array(query); - return 0; + if (results.RowCount() != 1) { + LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return nullptr; + } + + auto row = results.begin(); + + bool perl_enabled = atoi(row[11]) == 1 ? true : false; + + Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), + atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), + atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); + + spawn2_list.Insert(newSpawn); + + return newSpawn; } bool ZoneDatabase::CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value) From c70c7e13ec9510b09d33603b47ab14f5b6278b45 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:07:15 -0700 Subject: [PATCH 38/57] CreateSpawn2 converted to QueryDatabase --- zone/spawn2.cpp | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index e7e5e9e81..36ca4b3d6 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -413,38 +413,27 @@ Spawn2* ZoneDatabase::LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2 return newSpawn; } -bool ZoneDatabase::CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value) +bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - uint32 affected_rows = 0; - - // if(GetInverseXY()==1) { - // float temp=x; - // x=y; - // y=temp; - // } - if (RunQuery(query, MakeAnyLenString(&query, - "INSERT INTO spawn2 (spawngroupID,zone,x,y,z,heading,respawntime,variance,_condition,cond_value) Values (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)", - spawngroup, zone, x, y, z, heading, respawn, variance, condition, cond_value - ), errbuf, 0, &affected_rows)) { - safe_delete_array(query); - if (affected_rows == 1) { - if(c) c->LogSQL(query); - return true; - } - else { - return false; - } - } - else { - LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query, errbuf); - safe_delete_array(query); + std::string query = StringFormat("INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, " + "respawntime, variance, _condition, cond_value) " + "VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)", + spawngroup, zone, x, y, z, heading, + respawn, variance, condition, cond_value); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return false; - } + } - return false; + if (results.RowsAffected() != 1) + return false; + + if(client) + client->LogSQL(query.c_str()); + + return true; } uint32 Zone::CountSpawn2() { From 3cf4d4af1ba052d8cab8693ed3ad62ad02f8f5ed Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:10:15 -0700 Subject: [PATCH 39/57] UpdateDBEvent converted to QueryDatabase --- zone/spawn2.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 36ca4b3d6..f4cbe64a7 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -661,23 +661,20 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) { } void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - int len; - SpawnCondition cond; - len = MakeAnyLenString(&query, - "UPDATE spawn_events SET " - "next_minute=%d, next_hour=%d, next_day=%d, next_month=%d, " - "next_year=%d, enabled=%d, strict=%d " - "WHERE id=%d", - event.next.minute, event.next.hour, event.next.day, event.next.month, - event.next.year, event.enabled?1:0, event.strict?1:0,event.id - ); - if(!database.RunQuery(query, len, errbuf)) { - LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query, errbuf); - } - safe_delete_array(query); + std::string query = StringFormat("UPDATE spawn_events SET " + "next_minute = %d, next_hour = %d, " + "next_day = %d, next_month = %d, " + "next_year = %d, enabled = %d, " + "strict = %d WHERE id = %d", + event.next.minute, event.next.hour, + event.next.day, event.next.month, + event.next.year, event.enabled? 1: 0, + event.strict? 1: 0, event.id); + auto results = database.QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query.c_str(), results.ErrorMessage().c_str()); + } void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) { From 538921701c42252531987da8ecc12477068a9b79 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:13:11 -0700 Subject: [PATCH 40/57] UpdatedDBCondition converted to QueryDatabase --- zone/spawn2.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index f4cbe64a7..7440f07af 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -678,19 +678,15 @@ void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) { } void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - int len; - SpawnCondition cond; - len = MakeAnyLenString(&query, - "REPLACE INTO spawn_condition_values (id, value, zone, instance_id) VALUES(%u, %u, '%s', %u)", - cond_id, value, zone_name, instance_id - ); - if(!database.RunQuery(query, len, errbuf)) { - LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query, errbuf); - } - safe_delete_array(query); + std::string query = StringFormat("REPLACE INTO spawn_condition_values " + "(id, value, zone, instance_id) " + "VALUES( %u, %u, '%s', %u)", + cond_id, value, zone_name, instance_id); + auto results = database.QueryDatabase(query); + if(!results.Success()) + LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query.c_str(), results.ErrorMessage().c_str()); + } bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) { From 7864a5285de41f05315ce06803fe22a47e35a2ec Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:18:51 -0700 Subject: [PATCH 41/57] LoadDBEvent converted to QueryDatabase --- zone/spawn2.cpp | 78 +++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 7440f07af..752052f2c 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -690,49 +690,45 @@ void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 inst } bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - int len; - bool ret = false; - - len = MakeAnyLenString(&query, - "SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict,zone " - "FROM spawn_events WHERE id=%d", event_id); - if (database.RunQuery(query, len, errbuf, &result)) { - safe_delete_array(query); - if((row = mysql_fetch_row(result))) { - event.id = atoi(row[0]); - event.condition_id = atoi(row[1]); - event.period = atoi(row[2]); - - event.next.minute = atoi(row[3]); - event.next.hour = atoi(row[4]); - event.next.day = atoi(row[5]); - event.next.month = atoi(row[6]); - event.next.year = atoi(row[7]); - - event.enabled = atoi(row[8])==0?false:true; - event.action = (SpawnEvent::Action) atoi(row[9]); - event.argument = atoi(row[10]); - event.strict = atoi(row[11])==0?false:true; - zone_name = row[12]; - - std::string t; - EQTime::ToString(&event.next, t); - _log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s", - event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, t.c_str()); - - ret = true; - } - mysql_free_result(result); - } else { - LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query, errbuf); - safe_delete_array(query); + std::string query = StringFormat("SELECT id, cond_id, period, " + "next_minute, next_hour, next_day, " + "next_month, next_year, enabled, " + "action, argument, strict, zone " + "FROM spawn_events WHERE id = %d", event_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return false; } - return(ret); + + if (results.RowCount() == 0) + return false; + + auto row = results.begin(); + + event.id = atoi(row[0]); + event.condition_id = atoi(row[1]); + event.period = atoi(row[2]); + + event.next.minute = atoi(row[3]); + event.next.hour = atoi(row[4]); + event.next.day = atoi(row[5]); + event.next.month = atoi(row[6]); + event.next.year = atoi(row[7]); + + event.enabled = atoi(row[8]) != 0; + event.action = (SpawnEvent::Action) atoi(row[9]); + event.argument = atoi(row[10]); + event.strict = atoi(row[11]) != 0; + zone_name = row[12]; + + std::string timeAsString; + EQTime::ToString(&event.next, timeAsString); + + _log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, timeAsString.c_str()); + + return true; } bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) From 0240c6195252ebd55dbc16cc2dbb063becf6f78c Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:31:55 -0700 Subject: [PATCH 42/57] LoadSpawnConditions converted to QueryDatabase --- zone/spawn2.cpp | 210 +++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 111 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 752052f2c..1e233a36f 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -733,94 +733,87 @@ bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std: bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - int len; - //clear out old stuff.. spawn_conditions.clear(); - //load spawn conditions - SpawnCondition cond; - len = MakeAnyLenString(&query, "SELECT id, onchange, value FROM spawn_conditions WHERE zone='%s'", zone_name); - if (database.RunQuery(query, len, errbuf, &result)) { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) { - cond.condition_id = atoi(row[0]); - cond.value = atoi(row[2]); - cond.on_change = (SpawnCondition::OnChange) atoi(row[1]); - spawn_conditions[cond.condition_id] = cond; - _log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change); - } - mysql_free_result(result); - } else { - LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf); - safe_delete_array(query); + + std::string query = StringFormat("SELECT id, onchange, value " + "FROM spawn_conditions " + "WHERE zone = '%s'", zone_name); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return false; - } + } + + for (auto row = results.begin(); row != results.end(); ++row) { + //load spawn conditions + SpawnCondition cond; + + cond.condition_id = atoi(row[0]); + cond.value = atoi(row[2]); + cond.on_change = (SpawnCondition::OnChange) atoi(row[1]); + spawn_conditions[cond.condition_id] = cond; + + _log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change); + } //load values - len = MakeAnyLenString(&query, "SELECT id, value FROM spawn_condition_values WHERE zone='%s' and instance_id=%u", zone_name, instance_id); - if (database.RunQuery(query, len, errbuf, &result)) { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) - { - std::map::iterator iter = spawn_conditions.find(atoi(row[0])); - if(iter != spawn_conditions.end()) - { - iter->second.value = atoi(row[1]); - } - } - mysql_free_result(result); - } - else - { - LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf); - safe_delete_array(query); + query = StringFormat("SELECT id, value FROM spawn_condition_values " + "WHERE zone = '%s' AND instance_id = %u", + zone_name, instance_id); + results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); spawn_conditions.clear(); return false; - } + } + + for (auto row = results.begin(); row != results.end(); ++row) { + auto iter = spawn_conditions.find(atoi(row[0])); + + if(iter != spawn_conditions.end()) + iter->second.value = atoi(row[1]); + } //load spawn events - SpawnEvent event; - len = MakeAnyLenString(&query, - "SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict " - "FROM spawn_events WHERE zone='%s'", zone_name); - if (database.RunQuery(query, len, errbuf, &result)) { - safe_delete_array(query); - while((row = mysql_fetch_row(result))) { - event.id = atoi(row[0]); - event.condition_id = atoi(row[1]); - event.period = atoi(row[2]); - if(event.period == 0) { - LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id); - continue; - } - - event.next.minute = atoi(row[3]); - event.next.hour = atoi(row[4]); - event.next.day = atoi(row[5]); - event.next.month = atoi(row[6]); - event.next.year = atoi(row[7]); - - event.enabled = atoi(row[8])==0?false:true; - event.action = (SpawnEvent::Action) atoi(row[9]); - event.argument = atoi(row[10]); - event.strict = atoi(row[11])==0?false:true; - spawn_events.push_back(event); - - _log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", - event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict); - } - mysql_free_result(result); - } else { - LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query, errbuf); - safe_delete_array(query); + query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, " + "next_day, next_month, next_year, enabled, action, argument, strict " + "FROM spawn_events WHERE zone = '%s'", zone_name); + results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return false; - } + } + + for (auto row = results.begin(); row != results.end(); ++row) { + SpawnEvent event; + + event.id = atoi(row[0]); + event.condition_id = atoi(row[1]); + event.period = atoi(row[2]); + + if(event.period == 0) { + LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id); + continue; + } + + event.next.minute = atoi(row[3]); + event.next.hour = atoi(row[4]); + event.next.day = atoi(row[5]); + event.next.month = atoi(row[6]); + event.next.year = atoi(row[7]); + + event.enabled = atoi(row[8])==0?false:true; + event.action = (SpawnEvent::Action) atoi(row[9]); + event.argument = atoi(row[10]); + event.strict = atoi(row[11])==0?false:true; + + spawn_events.push_back(event); + + _log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict); + } //now we need to catch up on events that happened while we were away //and use them to alter just the condition variables. @@ -834,11 +827,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in TimeOfDay_Struct tod; zone->zone_time.getEQTimeOfDay(&tod); - std::vector::iterator cur,end; - cur = spawn_events.begin(); - end = spawn_events.end(); - bool ran; - for(; cur != end; ++cur) { + for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) { SpawnEvent &cevent = *cur; bool StrictCheck = false; @@ -853,43 +842,42 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in if(!cevent.enabled || !StrictCheck) SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0); - if(cevent.enabled) - { - //watch for special case of all 0s, which means to reset next to now - if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) { - _log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id); - memcpy(&cevent.next, &tod, sizeof(cevent.next)); - //add one period - EQTime::AddMinutes(cevent.period, &cevent.next); - //save it in the db. - UpdateDBEvent(cevent); - continue; //were done with this event. - } + if(!cevent.enabled) + continue; - ran = false; - while(EQTime::IsTimeBefore(&tod, &cevent.next)) { - _log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id); - //this event has been triggered. - //execute the event - if(!cevent.strict || StrictCheck) - ExecEvent(cevent, false); + //watch for special case of all 0s, which means to reset next to now + if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) { + _log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id); + memcpy(&cevent.next, &tod, sizeof(cevent.next)); + //add one period + EQTime::AddMinutes(cevent.period, &cevent.next); + //save it in the db. + UpdateDBEvent(cevent); + continue; //were done with this event. + } - //add the period of the event to the trigger time - EQTime::AddMinutes(cevent.period, &cevent.next); - ran = true; - } - //only write it out if the event actually ran - if(ran) { - //save the event in the DB - UpdateDBEvent(cevent); - } - } + bool ran = false; + while(EQTime::IsTimeBefore(&tod, &cevent.next)) { + _log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id); + //this event has been triggered. + //execute the event + if(!cevent.strict || StrictCheck) + ExecEvent(cevent, false); + + //add the period of the event to the trigger time + EQTime::AddMinutes(cevent.period, &cevent.next); + ran = true; + } + + //only write it out if the event actually ran + if(ran) + UpdateDBEvent(cevent); //save the event in the DB } //now our event timers are all up to date, find our closest event. FindNearestEvent(); - return(true); + return true; } void SpawnConditionManager::FindNearestEvent() { From b6875564d41c5c7bce10cab252a69b244bad663a Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 13:47:18 -0700 Subject: [PATCH 43/57] GetCondition converted to QueryDatabase --- zone/spawn2.cpp | 51 ++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 1e233a36f..25cbb8ccf 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -1129,37 +1129,28 @@ int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instanc } SpawnCondition &cond = condi->second; - return(cond.value); - } else { - //this is a remote spawn condition, grab it from the DB - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES *result; - MYSQL_ROW row; - int len; - - int16 value; - - //load spawn conditions - SpawnCondition cond; - len = MakeAnyLenString(&query, "SELECT value FROM spawn_condition_values WHERE zone='%s' AND instance_id=%u AND id=%d", - zone_short, instance_id, condition_id); - if (database.RunQuery(query, len, errbuf, &result)) { - safe_delete_array(query); - if((row = mysql_fetch_row(result))) { - value = atoi(row[0]); - } else { - _log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short); - value = 0; //dunno a better thing to do... - } - mysql_free_result(result); - } else { - _log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short); - safe_delete_array(query); - value = 0; //dunno a better thing to do... - } - return(value); + return cond.value; } + + //this is a remote spawn condition, grab it from the DB + //load spawn conditions + std::string query = StringFormat("SELECT value FROM spawn_condition_values " + "WHERE zone = '%s' AND instance_id = %u AND id = %d", + zone_short, instance_id, condition_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + _log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short); + return 0; //dunno a better thing to do... + } + + if (results.RowCount() == 0) { + _log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short); + return 0; //dunno a better thing to do... + } + + auto row = results.begin(); + + return atoi(row[0]); } bool SpawnConditionManager::Check(uint16 condition, int16 min_value) { From c851cd3f120d070996d3d73b238965cf5803a01b Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 14:06:52 -0700 Subject: [PATCH 44/57] Handle_OP_ItemLinkClick converted to QueryDatabase --- zone/client_packet.cpp | 55 +++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f35ec0565..5ec2e9e9e 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3137,6 +3137,7 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) DumpPacket(app); return; } + DumpPacket(app); ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer; @@ -3156,30 +3157,24 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) silentsaylink = true; } - if (sayid && sayid > 0) + if (sayid > 0) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - MYSQL_ROW row; + std::string query = StringFormat("SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); + return; + } - if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid),errbuf,&result)) - { - if (mysql_num_rows(result) == 1) - { - row = mysql_fetch_row(result); - response = row[0]; - } - mysql_free_result(result); - } - else - { - Message(13, "Error: The saylink (%s) was not found in the database.",response.c_str()); - safe_delete_array(query); + if (results.RowCount() != 1) { + Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); return; } - safe_delete_array(query); + + auto row = results.begin(); + response = row[0]; + } if((response).size() > 0) @@ -4628,7 +4623,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime); } - + if (spell_to_cast > 0) // if we've matched LoH or HT, cast now CastSpell(spell_to_cast, castspell->target_id, castspell->slot); } @@ -5864,9 +5859,9 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) else this->DeleteItemInInventory(mp->itemslot,mp->quantity,false); - //This forces the price to show up correctly for charged items. + //This forces the price to show up correctly for charged items. if(inst->IsCharged()) - mp->quantity = 1; + mp->quantity = 1; EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerSell, sizeof(Merchant_Purchase_Struct)); Merchant_Purchase_Struct* mco=(Merchant_Purchase_Struct*)outapp->pBuffer; @@ -7635,7 +7630,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) int mendhp = GetMaxHP() / 4; int currenthp = GetHP(); if (MakeRandomInt(0, 199) < (int)GetSkill(SkillMend)) { - + int criticalchance = spellbonuses.CriticalMend + itembonuses.CriticalMend + aabonuses.CriticalMend; if(MakeRandomInt(0,99) < criticalchance){ @@ -9532,7 +9527,7 @@ void Client::CompleteConnect() { /* This sub event is for if a player logs in for the first time since entering world. */ if (firstlogon == 1){ - parse->EventPlayer(EVENT_CONNECT, this, "", 0); + parse->EventPlayer(EVENT_CONNECT, this, "", 0); /* QS: PlayerLogConnectDisconnect */ if (RuleB(QueryServ, PlayerLogConnectDisconnect)){ std::string event_desc = StringFormat("Connect :: Logged into zoneid:%i instid:%i", this->GetZoneID(), this->GetInstanceID()); @@ -12775,7 +12770,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) { QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc); } } - } + } /* Cursor to Item storage */ else { uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id); @@ -12784,7 +12779,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) { if(reclaim->count > max_currency) { SummonItem(item_id, max_currency); SetAlternateCurrencyValue(reclaim->currency_id, 0); - } + } else { SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, false, MainCursor); AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count)); @@ -12793,7 +12788,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) { if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){ std::string event_desc = StringFormat("Reclaim :: Cursor to Item :: alt_currency_id:%i amount:-%i in zoneid:%i instid:%i", reclaim->currency_id, reclaim->count, this->GetZoneID(), this->GetInstanceID()); QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc); - } + } } } @@ -12885,8 +12880,8 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) { /* QS: PlayerLogAlternateCurrencyTransactions :: Sold to Merchant*/ if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){ std::string event_desc = StringFormat("Sold to Merchant :: itemid:%u npcid:%u alt_currency_id:%u cost:%u in zoneid:%u instid:%i", item->ID, npc_id, alt_cur_id, cost, this->GetZoneID(), this->GetInstanceID()); - QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc); - } + QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc); + } FastQueuePacket(&outapp); AddAlternateCurrencyValue(alt_cur_id, cost); @@ -12947,7 +12942,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) switch(Command) { case 0: - { + { VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_PlayerToggle_Struct); LFGuild_PlayerToggle_Struct *pts = (LFGuild_PlayerToggle_Struct *)app->pBuffer; From 4d0179d525633175548a71b9b0182fd16c6e8588 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 14:13:06 -0700 Subject: [PATCH 45/57] Handle_OP_SetStartCity converted to QueryDatabase --- zone/client_packet.cpp | 102 ++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5ec2e9e9e..3ab2338c7 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11405,92 +11405,68 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) Message(15,"Your home city has already been set.", m_pp.binds[4].zoneId, database.GetZoneName(m_pp.binds[4].zoneId)); return; } + if (app->size < 1) { LogFile->write(EQEMuLog::Error, "Wrong size: OP_SetStartCity, size=%i, expected %i", app->size, 1); DumpPacket(app); return; } - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result = nullptr; - MYSQL_ROW row = 0; float x(0),y(0),z(0); uint32 zoneid = 0; + uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); - uint32 StartCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); - bool ValidCity = false; - database.RunQuery - ( - query, - MakeAnyLenString - ( - &query, - "SELECT zone_id, bind_id, x, y, z FROM start_zones " - "WHERE player_class=%i AND player_deity=%i AND player_race=%i", - m_pp.class_, - m_pp.deity, - m_pp.race - ), - errbuf, - &result - ); - safe_delete_array(query); - - if(!result) { + std::string query = StringFormat("SELECT zone_id, bind_id, x, y, z FROM start_zones " + "WHERE player_class=%i AND player_deity=%i AND player_race=%i", + m_pp.class_, m_pp.deity, m_pp.race); + auto results = database.QueryDatabase(query); + if(!results.Success()) { LogFile->write(EQEMuLog::Error, "No valid start zones found for /setstartcity"); return; } - while(row = mysql_fetch_row(result)) { + bool validCity = false; + for (auto row = results.begin(); row != results.end(); ++row) { if(atoi(row[1]) != 0) zoneid = atoi(row[1]); else zoneid = atoi(row[0]); - if(zoneid == StartCity) { - ValidCity = true; - x = atof(row[2]); - y = atof(row[3]); - z = atof(row[4]); - } + if(zoneid != startCity) + continue; + + validCity = true; + x = atof(row[2]); + y = atof(row[3]); + z = atof(row[4]); } - if(ValidCity) { + if(validCity) { Message(15,"Your home city has been set"); - SetStartZone(StartCity, x, y, z); - } - else { - database.RunQuery - ( - query, - MakeAnyLenString - ( - &query, - "SELECT zone_id, bind_id FROM start_zones " - "WHERE player_class=%i AND player_deity=%i AND player_race=%i", - m_pp.class_, - m_pp.deity, - m_pp.race - ), - errbuf, - &result - ); - safe_delete_array(query); - Message(15,"Use \"/startcity #\" to choose a home city from the following list:"); - char* name; - while(row = mysql_fetch_row(result)) { - if(atoi(row[1]) != 0) - zoneid = atoi(row[1]); - else - zoneid = atoi(row[0]); - database.GetZoneLongName(database.GetZoneName(zoneid),&name); - Message(15,"%d - %s", zoneid, name); - safe_delete_array(name); - } + SetStartZone(startCity, x, y, z); + return; } - mysql_free_result(result); + query = StringFormat("SELECT zone_id, bind_id FROM start_zones " + "WHERE player_class=%i AND player_deity=%i AND player_race=%i", + m_pp.class_, m_pp.deity, m_pp.race); + results = database.QueryDatabase(query); + if (!results.Success()) + return; + + Message(15,"Use \"/startcity #\" to choose a home city from the following list:"); + + for (auto row = results.begin(); row != results.end(); ++row) { + if(atoi(row[1]) != 0) + zoneid = atoi(row[1]); + else + zoneid = atoi(row[0]); + + char* name; + database.GetZoneLongName(database.GetZoneName(zoneid), &name); + Message(15,"%d - %s", zoneid, name); + } + } void Client::Handle_OP_Report(const EQApplicationPacket *app) From f948786f6a22b16abc76bc13ceb3874fc7d557ac Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 14:21:33 -0700 Subject: [PATCH 46/57] Handle_OP_GMSearchCorpse converted to QueryDatabase --- zone/client_packet.cpp | 101 ++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 62 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 3ab2338c7..7cc3ebe85 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11573,7 +11573,7 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app) // Could make this into a rule, although there is a hard limit since we are using a popup, of 4096 bytes that can // be displayed in the window, including all the HTML formatting tags. // - const int MaxResults = 10; + const int maxResults = 10; if(app->size < sizeof(GMSearchCorpse_Struct)) { @@ -11586,85 +11586,62 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app) GMSearchCorpse_Struct *gmscs = (GMSearchCorpse_Struct *)app->pBuffer; gmscs->Name[63] = '\0'; - char errbuf[MYSQL_ERRMSG_SIZE]; - char* Query = 0; - MYSQL_RES *Result; - MYSQL_ROW Row; + char *escSearchString = new char[129]; + database.DoEscapeString(escSearchString, gmscs->Name, strlen(gmscs->Name)); - char *EscSearchString = new char[129]; + std::string query = StringFormat("SELECT charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried " + "FROM player_corpses WheRE charname LIKE '%%%s%%' ORDER BY charname LIMIT %i", + escSearchString, maxResults); + safe_delete_array(escSearchString); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Message(0, "Query failed: %s.", results.ErrorMessage().c_str()); + return; + } - database.DoEscapeString(EscSearchString, gmscs->Name, strlen(gmscs->Name)); + if (results.RowCount() == 0) + return; - if (database.RunQuery(Query, MakeAnyLenString(&Query, "select charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried from " - "player_corpses where charname like '%%%s%%' order by charname limit %i", - EscSearchString, MaxResults), errbuf, &Result)) - { + if(results.RowCount() == maxResults) + Message(clientMessageError, "Your search found too many results; some are not displayed."); + else + Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.", results.RowCount(), gmscs->Name); - int NumberOfRows = mysql_num_rows(Result); + char charName[64], timeOfDeath[20]; - if(NumberOfRows == MaxResults) - Message(clientMessageError, "Your search found too many results; some are not displayed."); - else { - Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.", - NumberOfRows, gmscs->Name); - } - - if(NumberOfRows == 0) - { - mysql_free_result(Result); - safe_delete_array(Query); - return; - } - - char CharName[64], TimeOfDeath[20], Buffer[512]; - - std::string PopupText = "
NameZoneXYZDate" + std::string popupText = ""; + for (auto row = results.begin(); row != results.end(); ++row) { - while ((Row = mysql_fetch_row(Result))) - { + strn0cpy(charName, row[0], sizeof(charName)); - strn0cpy(CharName, Row[0], sizeof(CharName)); + uint32 ZoneID = atoi(row[1]); + float CorpseX = atof(row[2]); + float CorpseY = atof(row[3]); + float CorpseZ = atof(row[4]); - uint32 ZoneID = atoi(Row[1]); + strn0cpy(timeOfDeath, row[5], sizeof(timeOfDeath)); - float CorpseX = atof(Row[2]); - float CorpseY = atof(Row[3]); - float CorpseZ = atof(Row[4]); + bool corpseRezzed = atoi(row[6]); + bool corpseBuried = atoi(row[7]); - strn0cpy(TimeOfDeath, Row[5], sizeof(TimeOfDeath)); + popupText += StringFormat("", + charName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, timeOfDeath, + corpseRezzed ? "Yes" : "No", corpseBuried ? "Yes" : "No"); - bool CorpseRezzed = atoi(Row[6]); - bool CorpseBuried = atoi(Row[7]); + if(popupText.size() > 4000) { + Message(clientMessageError, "Unable to display all the results."); + break; + } - sprintf(Buffer, "", - CharName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, TimeOfDeath, - CorpseRezzed ? "Yes" : "No", CorpseBuried ? "Yes" : "No"); + } - PopupText += Buffer; + popupText += "
NameZoneXYZDate" "RezzedBuried
 " "
%s%s%8.0f%8.0f%8.0f%s%s%s
%s%s%8.0f%8.0f%8.0f%s%s%s
"; - if(PopupText.size() > 4000) - { - Message(clientMessageError, "Unable to display all the results."); - break; - } + SendPopupToClient("Corpses", popupText.c_str()); - } - - PopupText += "
"; - - mysql_free_result(Result); - - SendPopupToClient("Corpses", PopupText.c_str()); - } - else{ - Message(0, "Query failed: %s.", errbuf); - - } - safe_delete_array(Query); - safe_delete_array(EscSearchString); } void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) From 50e6d0d256a62ca06d52142bf50eb3f4f6dc9087 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 24 Aug 2014 16:02:21 -0700 Subject: [PATCH 47/57] Load converted to QueryDatabase --- zone/guild_mgr.cpp | 146 +++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 92 deletions(-) diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 087878ffc..876feb4bd 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -644,104 +644,66 @@ GuildBankManager::~GuildBankManager() } } -bool GuildBankManager::Load(uint32 GuildID) +bool GuildBankManager::Load(uint32 guildID) { - const char *LoadQuery = "SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` from `guild_bank` " - "WHERE `guildid` = %i"; - - char errbuf[MYSQL_ERRMSG_SIZE]; - - char* query = 0; - - MYSQL_RES *result; - - MYSQL_ROW row; - - if(database.RunQuery(query, MakeAnyLenString(&query, LoadQuery, GuildID), errbuf, &result)) - { - GuildBank *Bank = new GuildBank; - - Bank->GuildID = GuildID; - - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - Bank->Items.MainArea[i].ItemID = 0; - - for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) - Bank->Items.DepositArea[i].ItemID = 0; - - char Donator[64], WhoFor[64]; - - while((row = mysql_fetch_row(result))) - { - int Area = atoi(row[0]); - - int Slot = atoi(row[1]); - - int ItemID = atoi(row[2]); - - int Qty = atoi(row[3]); - - if(row[4]) - strn0cpy(Donator, row[4], sizeof(Donator)); - else - Donator[0] = '\0'; - - int Permissions = atoi(row[5]); - - if(row[6]) - strn0cpy(WhoFor, row[6], sizeof(WhoFor)); - else - WhoFor[0] = '\0'; - - if(Area == GuildBankMainArea) - { - if((Slot >= 0) && (Slot < GUILD_BANK_MAIN_AREA_SIZE)) - { - Bank->Items.MainArea[Slot].ItemID = ItemID; - - Bank->Items.MainArea[Slot].Quantity = Qty; - - strn0cpy(Bank->Items.MainArea[Slot].Donator, Donator, sizeof(Donator)); - - Bank->Items.MainArea[Slot].Permissions = Permissions; - - strn0cpy(Bank->Items.MainArea[Slot].WhoFor, WhoFor, sizeof(WhoFor)); - } - } - else - { - if((Slot >= 0 ) && (Slot < GUILD_BANK_DEPOSIT_AREA_SIZE)) - { - Bank->Items.DepositArea[Slot].ItemID = ItemID; - - Bank->Items.DepositArea[Slot].Quantity = Qty; - - strn0cpy(Bank->Items.DepositArea[Slot].Donator, Donator, sizeof(Donator)); - - Bank->Items.DepositArea[Slot].Permissions = Permissions; - - strn0cpy(Bank->Items.DepositArea[Slot].WhoFor, WhoFor, sizeof(WhoFor)); - } - } - - } - mysql_free_result(result); - - safe_delete_array(query); - - Banks.push_back(Bank); - } - else - { - _log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query, errbuf); - - safe_delete_array(query); + std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` " + "FROM `guild_bank` WHERE `guildid` = %i", guildID); + auto results = database.QueryDatabase(query); + if(!results.Success()) { + _log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - return true; + GuildBank *bank = new GuildBank; + bank->GuildID = guildID; + + for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) + bank->Items.MainArea[i].ItemID = 0; + + for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) + bank->Items.DepositArea[i].ItemID = 0; + + char donator[64], whoFor[64]; + + for (auto row = results.begin(); row != results.end(); ++row) + { + int area = atoi(row[0]); + int slot = atoi(row[1]); + int itemID = atoi(row[2]); + int qty = atoi(row[3]); + + if(row[4]) + strn0cpy(donator, row[4], sizeof(donator)); + else + donator[0] = '\0'; + + int permissions = atoi(row[5]); + + if(row[6]) + strn0cpy(whoFor, row[6], sizeof(whoFor)); + else + whoFor[0] = '\0'; + + if(slot < 0 || + ((area != GuildBankMainArea || slot >= GUILD_BANK_MAIN_AREA_SIZE) || + (area == GuildBankMainArea || slot >= GUILD_BANK_DEPOSIT_AREA_SIZE))) + continue; + + bank->Items.MainArea[slot].ItemID = itemID; + bank->Items.MainArea[slot].Quantity = qty; + + strn0cpy(bank->Items.MainArea[slot].Donator, donator, sizeof(donator)); + + bank->Items.MainArea[slot].Permissions = permissions; + + strn0cpy(bank->Items.MainArea[slot].WhoFor, whoFor, sizeof(whoFor)); + } + + Banks.push_back(bank); + + return true; } bool GuildBankManager::IsLoaded(uint32 GuildID) From b3ea7ecd0d8f8ed01f24226ef95f817689f85d29 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 24 Aug 2014 19:11:41 -0400 Subject: [PATCH 48/57] Added param to special attack NPC_NO_CHASE Param 2 = If set will disable LOS check --- zone/aggro.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 109720e47..30ef4087d 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -877,8 +877,12 @@ bool Mob::CombatRange(Mob* other) if (GetSpecialAbility(NPC_CHASE_DISTANCE)){ + bool DoLoSCheck = true; float max_dist = static_cast(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0)); float min_dist = static_cast(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1)); + + if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2)); + DoLoSCheck = false; //Ignore line of sight check if (max_dist == 1) max_dist = 250.0f; //Default it to 250 if you forget to put a value @@ -890,7 +894,7 @@ bool Mob::CombatRange(Mob* other) else min_dist = min_dist * min_dist; - if (CheckLastLosState() && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist)) + if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist)) SetPseudoRoot(true); else SetPseudoRoot(false); From 00852063c2990fce2dcef0d01e203ec3b301ebb0 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Mon, 25 Aug 2014 12:15:06 -0700 Subject: [PATCH 49/57] Promote converted to QueryDatabase --- zone/guild_mgr.cpp | 81 ++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 876feb4bd..316ec6409 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -935,90 +935,73 @@ bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 return true; } -int GuildBankManager::Promote(uint32 GuildID, int SlotID) +int GuildBankManager::Promote(uint32 guildID, int slotID) { - if((SlotID < 0) || (SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) + if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))) return -1; - std::list::iterator Iterator = GetGuildBank(GuildID); + auto iter = GetGuildBank(guildID); - if(Iterator == Banks.end()) - { + if(iter == Banks.end()) return -1; - } - if((*Iterator)->Items.DepositArea[SlotID].ItemID == 0) - { + if((*iter)->Items.DepositArea[slotID].ItemID == 0) return -1; - } - int MainSlot = -1; + int mainSlot = -1; for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - if((*Iterator)->Items.MainArea[i].ItemID == 0) - { - MainSlot = i; - + if((*iter)->Items.MainArea[i].ItemID == 0) { + mainSlot = i; break; } - if(MainSlot == -1) + if(mainSlot == -1) return -1; + (*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID; + (*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity; + (*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions; - (*Iterator)->Items.MainArea[MainSlot].ItemID = (*Iterator)->Items.DepositArea[SlotID].ItemID; - - (*Iterator)->Items.MainArea[MainSlot].Quantity = (*Iterator)->Items.DepositArea[SlotID].Quantity; - - strn0cpy((*Iterator)->Items.MainArea[MainSlot].Donator, (*Iterator)->Items.DepositArea[SlotID].Donator, sizeof((*Iterator)->Items.MainArea[MainSlot].Donator)); - (*Iterator)->Items.MainArea[MainSlot].Permissions = (*Iterator)->Items.DepositArea[SlotID].Permissions; - - strn0cpy((*Iterator)->Items.MainArea[MainSlot].WhoFor, (*Iterator)->Items.DepositArea[SlotID].WhoFor, sizeof((*Iterator)->Items.MainArea[MainSlot].WhoFor)); - - const char *Query="UPDATE `guild_bank` SET `area` = 1, `slot` = %i WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i LIMIT 1"; - - char errbuf[MYSQL_ERRMSG_SIZE]; - - char* query = 0; - - if(!database.RunQuery(query, MakeAnyLenString(&query, Query, MainSlot, GuildID, SlotID), errbuf)) - { - _log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query, errbuf); - - safe_delete_array(query); + strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator)); + strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor)); + std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i " + "WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i " + "LIMIT 1", mainSlot, guildID, slotID); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + _log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query.c_str(), results.ErrorMessage().c_str()); return -1; } - safe_delete_array(query); + (*iter)->Items.DepositArea[slotID].ItemID = 0; - (*Iterator)->Items.DepositArea[SlotID].ItemID = 0; - - const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[MainSlot].ItemID); + const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID); GuildBankItemUpdate_Struct gbius; if(!Item->Stackable) - gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0); + gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0); else { - if((*Iterator)->Items.MainArea[MainSlot].Quantity == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 0, 0); + if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize) + gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, + (*iter)->Items.MainArea[mainSlot].Quantity, 0, 0, 0); else - gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 1, 0); + gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, + (*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0); } strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); + entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); - gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0); + gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0); - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); + entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); - return MainSlot; + return mainSlot; } void GuildBankManager::SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName) From c3fdbfe90469f4f46aef164c279fa1387675191d Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Mon, 25 Aug 2014 12:33:09 -0700 Subject: [PATCH 50/57] SetPermissions converted to QueryDatabase --- zone/guild_mgr.cpp | 68 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 316ec6409..3f477df6f 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -1004,70 +1004,58 @@ int GuildBankManager::Promote(uint32 guildID, int slotID) return mainSlot; } -void GuildBankManager::SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName) +void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName) { - if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) + if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))) return; - std::list::iterator Iterator = GetGuildBank(GuildID); + auto iter = GetGuildBank(guildID); - if(Iterator == Banks.end()) + if(iter == Banks.end()) + return; + + if((*iter)->Items.MainArea[slotID].ItemID == 0) + return; + + std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' " + "WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1", + permissions, memberName, guildID, slotID); + auto results = database.QueryDatabase(query); + if(!results.Success()) { + _log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query.c_str(), results.ErrorMessage().c_str()); return; } - if((*Iterator)->Items.MainArea[SlotID].ItemID == 0) - { - return; - } + (*iter)->Items.MainArea[slotID].Permissions = permissions; - const char *Query="UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1"; - - char errbuf[MYSQL_ERRMSG_SIZE]; - - char* query = 0; - - if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Permissions, MemberName, GuildID, SlotID), errbuf)) - { - _log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query, errbuf); - - safe_delete_array(query); - - return; - } - - safe_delete_array(query); - - (*Iterator)->Items.MainArea[SlotID].Permissions = Permissions; - - if(Permissions == GuildBankSingleMember) - strn0cpy((*Iterator)->Items.MainArea[SlotID].WhoFor, MemberName, sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor)); + if(permissions == GuildBankSingleMember) + strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor)); else - (*Iterator)->Items.MainArea[SlotID].WhoFor[0] = '\0'; + (*iter)->Items.MainArea[slotID].WhoFor[0] = '\0'; - - const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[SlotID].ItemID); + const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID); GuildBankItemUpdate_Struct gbius; if(!Item->Stackable) - gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0); + gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0); else { - if((*Iterator)->Items.MainArea[SlotID].Quantity == Item->StackSize) - gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0); + if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize) + gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, + (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 0, 0); else - gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 1, 0); + gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, + (*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0); } strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - strn0cpy(gbius.WhoFor, (*Iterator)->Items.MainArea[SlotID].WhoFor, sizeof(gbius.WhoFor)); + strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor)); - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); + entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); } ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) From 1e870864716ff9b7da32323cc94c7941cd944e60 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Mon, 25 Aug 2014 12:43:14 -0700 Subject: [PATCH 51/57] DeleteItem converted to QueryDatabase --- zone/guild_mgr.cpp | 85 +++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 3f477df6f..e1fbf0db5 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -1141,90 +1141,73 @@ std::list::iterator GuildBankManager::GetGuildBank(uint32 GuildID) return Iterator; } -bool GuildBankManager::DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) +bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto iter = GetGuildBank(guildID); - if(Iterator == Banks.end()) + if(iter == Banks.end()) return false; - char errbuf[MYSQL_ERRMSG_SIZE]; - - char* query = 0; - GuildBankItem* BankArea = nullptr; - if(Area == GuildBankMainArea) + if(area == GuildBankMainArea) { - if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) + if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) return false; - BankArea = &(*Iterator)->Items.MainArea[0]; - } - else - { - if(SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)) + BankArea = &(*iter)->Items.MainArea[0]; + } else { + if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)) return false; - BankArea = &(*Iterator)->Items.DepositArea[0]; + BankArea = &(*iter)->Items.DepositArea[0]; } + bool deleted = true; - bool Deleted = true; - - const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID); - - if(!Item->Stackable || (Quantity >= BankArea[SlotID].Quantity)) - { - const char *Query = "DELETE from `guild_bank` where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1"; - - if(!database.RunQuery(query, MakeAnyLenString(&query, Query, GuildID, Area, SlotID), errbuf)) - { - _log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query, errbuf); - - safe_delete_array(query); + const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID); + if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) { + std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i " + "AND `area` = %i AND `slot` = %i LIMIT 1", + guildID, area, slotID); + auto results = database.QueryDatabase(query); + if(!results.Success()) { + _log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - safe_delete_array(query); - - BankArea[SlotID].ItemID = 0; - } - else - { - const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1"; - - if(!database.RunQuery(query, MakeAnyLenString(&query, Query, BankArea[SlotID].Quantity - Quantity, - GuildID, Area, SlotID), errbuf)) - { - _log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query, errbuf); - - safe_delete_array(query); + BankArea[slotID].ItemID = 0; + } else { + std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i " + "AND `area` = %i AND `slot` = %i LIMIT 1", + BankArea[slotID].Quantity - quantity, guildID, area, slotID); + auto results = database.QueryDatabase(query); + if(!results.Success()) { + _log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str()); return false; } - safe_delete_array(query); + BankArea[slotID].Quantity -= quantity; - BankArea[SlotID].Quantity -= Quantity; - - Deleted = false; + deleted = false; } + GuildBankItemUpdate_Struct gbius; - if(!Deleted) + if(!deleted) { - gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 1, Item->ID, Item->Icon, BankArea[SlotID].Quantity, BankArea[SlotID].Permissions, 1, 0); + gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0); strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName)); - strn0cpy(gbius.WhoFor, BankArea[SlotID].WhoFor, sizeof(gbius.WhoFor)); + strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor)); } else - gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 0, 0, 0, 0, 0, 0, 0); + gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0); - entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID); + entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID); return true; From a6b923a22ef19fb610d33b99e9e2f681ecf54379 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Mon, 25 Aug 2014 15:10:46 -0700 Subject: [PATCH 52/57] UpdateItemQuantity converted to QueryDatabase --- zone/guild_mgr.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index e1fbf0db5..37cc7a3de 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -1338,26 +1338,20 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity return true; } -void GuildBankManager::UpdateItemQuantity(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) +void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity) { // Helper method for MergeStacks. Assuming all passed parameters are valid. // - char errbuf[MYSQL_ERRMSG_SIZE]; - - char* query = 0; - - const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1"; - - if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Quantity, GuildID, Area, SlotID), errbuf)) - { - _log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query, errbuf); - - safe_delete_array(query); - + std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i " + "WHERE `guildid` = %i AND `area` = %i " + "AND `slot` = %i LIMIT 1", + quantity, guildID, area, slotID); + auto results = database.QueryDatabase(query); + if(!results.Success()) { + _log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query.c_str(), results.ErrorMessage().c_str()); return; } - safe_delete_array(query); } bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name) From d4a9fed45eeae224f64dfaa93bb3920af19a6cff Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 25 Aug 2014 22:29:00 -0400 Subject: [PATCH 53/57] Added QS code to Client::FinishTrade() --- zone/client.h | 2 +- zone/client_packet.cpp | 75 +++++++--- zone/trading.cpp | 320 +++++++++++++++++++++++++---------------- 3 files changed, 250 insertions(+), 147 deletions(-) diff --git a/zone/client.h b/zone/client.h index f2d16ea0f..d3aed5540 100644 --- a/zone/client.h +++ b/zone/client.h @@ -268,7 +268,7 @@ public: void TradeRequestFailed(const EQApplicationPacket* app); void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app); void TraderUpdate(uint16 slot_id,uint32 trader_id); - void FinishTrade(Mob* with, ServerPacket* qspack = nullptr, bool finalizer = false); + void FinishTrade(Mob* with, bool finalizer = false, void* event_entry = nullptr, std::list* event_details = nullptr); void SendZonePoints(); void SendBuyerResults(char *SearchQuery, uint32 SearchID); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f35ec0565..8d39f815a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4862,6 +4862,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) { Mob* with = trade->With(); trade->state = TradeAccepted; + if (with && with->IsClient()) { //finish trade... // Have both accepted? @@ -4872,6 +4873,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) other->trade->state = TradeCompleting; trade->state = TradeCompleting; + // should we do this for NoDrop items as well? if (CheckTradeLoreConflict(other) || other->CheckTradeLoreConflict(this)) { Message_StringID(13, TRADE_CANCEL_LORE); other->Message_StringID(13, TRADE_CANCEL_LORE); @@ -4887,23 +4889,37 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) // start QS code if(RuleB(QueryServ, PlayerLogTrades)) { - uint16 trade_count = 0; + QSPlayerLogTrade_Struct event_entry; + std::list event_details; - // Item trade count for packet sizing - for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) { - if(other->GetInv().GetItem(slot_id)) { trade_count += other->GetInv().GetItem(slot_id)->GetTotalItemCount(); } - if(m_inv[slot_id]) { trade_count += m_inv[slot_id]->GetTotalItemCount(); } - } - - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct) + (sizeof(QSTradeItems_Struct) * trade_count)); + memset(&event_entry, 0, sizeof(QSPlayerLogTrade_Struct)); // Perform actual trade - this->FinishTrade(other, qspack, true); - other->FinishTrade(this, qspack, false); + this->FinishTrade(other, true, &event_entry, &event_details); + other->FinishTrade(this, false, &event_entry, &event_details); - qspack->Deflate(); - if(worldserver.Connected()) { worldserver.SendPacket(qspack); } - safe_delete(qspack); + ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_details.size())); + + QSPlayerLogTrade_Struct* qs_buf = (QSPlayerLogTrade_Struct*)qs_pack->pBuffer; + + memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogTrade_Struct)); + + int offset = 0; + + for (std::list::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { + QSTradeItems_Struct* detail = reinterpret_cast(*iter); + qs_buf->items[offset] = *detail; + safe_delete(detail); + } + + event_details.clear(); + + qs_pack->Deflate(); + + if(worldserver.Connected()) + worldserver.SendPacket(qs_pack); + + safe_delete(qs_pack); // end QS code } else { @@ -4928,25 +4944,42 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) if(with->IsNPC()) { // Audit trade to database for player trade stream if(RuleB(QueryServ, PlayerLogHandins)) { - uint16 handin_count = 0; + QSPlayerLogHandin_Struct event_entry; + std::list event_details; - for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) { - if(m_inv[slot_id]) { handin_count += m_inv[slot_id]->GetTotalItemCount(); } + memset(&event_entry, 0, sizeof(QSPlayerLogHandin_Struct)); + + FinishTrade(with->CastToNPC(), false, &event_entry, &event_details); + + ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_details.size())); + + QSPlayerLogHandin_Struct* qs_buf = (QSPlayerLogHandin_Struct*)qs_pack->pBuffer; + + memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogHandin_Struct)); + + int offset = 0; + + for (std::list::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { + QSHandinItems_Struct* detail = reinterpret_cast(*iter); + qs_buf->items[offset] = *detail; + safe_delete(detail); } - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct) + (sizeof(QSHandinItems_Struct) * handin_count)); + event_details.clear(); - FinishTrade(with->CastToNPC(), qspack); + qs_pack->Deflate(); - qspack->Deflate(); - if(worldserver.Connected()) { worldserver.SendPacket(qspack); } - safe_delete(qspack); + if(worldserver.Connected()) + worldserver.SendPacket(qs_pack); + + safe_delete(qs_pack); } else { FinishTrade(with->CastToNPC()); } } #ifdef BOTS + // TODO: Log Bot trades else if(with->IsBot()) with->CastToBot()->FinishTrade(this, Bot::BotTradeClientNormal); #endif diff --git a/zone/trading.cpp b/zone/trading.cpp index 1ae9596b9..88b277651 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -22,7 +22,10 @@ #include "../common/rulesys.h" #include "quest_parser_collection.h" #include "worldserver.h" +#include "queryserv.h" + extern WorldServer worldserver; +extern QueryServ* QServ; // The maximum amount of a single bazaar/barter transaction expressed in copper. // Equivalent to 2 Million plat @@ -438,92 +441,38 @@ void Client::ResetTrade() { } } -void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) { +void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, std::list* event_details) { if(tradingWith && tradingWith->IsClient()) { Client* other = tradingWith->CastToClient(); + QSPlayerLogTrade_Struct* qs_audit = nullptr; + bool qs_log = false; if(other) { mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName()); this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true); - + // step 0: pre-processing // QS code - if (qspack && RuleB(QueryServ, PlayerLogTrades)) { - QSPlayerLogTrade_Struct* qsaudit = (QSPlayerLogTrade_Struct*)qspack->pBuffer; - + if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) { + qs_audit = (QSPlayerLogTrade_Struct*)event_entry; + qs_log = true; + if (finalizer) { - qsaudit->char2_id = this->character_id; + qs_audit->char2_id = this->character_id; - qsaudit->char2_money.platinum = this->trade->pp; - qsaudit->char2_money.gold = this->trade->gp; - qsaudit->char2_money.silver = this->trade->sp; - qsaudit->char2_money.copper = this->trade->cp; + qs_audit->char2_money.platinum = this->trade->pp; + qs_audit->char2_money.gold = this->trade->gp; + qs_audit->char2_money.silver = this->trade->sp; + qs_audit->char2_money.copper = this->trade->cp; } else { - qsaudit->char1_id = this->character_id; + qs_audit->char1_id = this->character_id; - qsaudit->char1_money.platinum = this->trade->pp; - qsaudit->char1_money.gold = this->trade->gp; - qsaudit->char1_money.silver = this->trade->sp; - qsaudit->char1_money.copper = this->trade->cp; - } - - // qsaudit->items[x].to_slot is disabled until QueryServ:PlayerLogTrades code is updated - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { - const ItemInst* inst = m_inv[trade_slot]; - - if (!inst) - continue; - - uint16 item_offset = qsaudit->char1_count + qsaudit->char2_count; - - qsaudit->items[item_offset].from_id = this->character_id; - qsaudit->items[item_offset].from_slot = trade_slot; - qsaudit->items[item_offset].to_id = other->CharacterID(); - qsaudit->items[item_offset].to_slot = 0; // disabled - qsaudit->items[item_offset].item_id = inst->GetID(); - qsaudit->items[item_offset].charges = inst->GetCharges(); - qsaudit->items[item_offset].aug_1 = inst->GetAugmentItemID(1); - qsaudit->items[item_offset].aug_2 = inst->GetAugmentItemID(2); - qsaudit->items[item_offset].aug_3 = inst->GetAugmentItemID(3); - qsaudit->items[item_offset].aug_4 = inst->GetAugmentItemID(4); - qsaudit->items[item_offset].aug_5 = inst->GetAugmentItemID(5); - - if (finalizer) - ++qsaudit->char2_count; - else - ++qsaudit->char1_count; - - if (inst->IsType(ItemClassContainer)) { - // Pseudo-Slot ID's are generated based on how the db saves bag items... - for (uint8 sub_slot = SUB_BEGIN; sub_slot < inst->GetItem()->BagSlots; ++sub_slot) { - const ItemInst* sub_inst = inst->GetItem(sub_slot); - - if (!sub_inst) - continue; - - int16 from_slot = Inventory::CalcSlotId(trade_slot, sub_slot); - item_offset = qsaudit->char1_count + qsaudit->char2_count; - - qsaudit->items[item_offset].from_id = this->character_id; - qsaudit->items[item_offset].from_slot = from_slot; - qsaudit->items[item_offset].to_id = other->CharacterID(); - qsaudit->items[item_offset].to_slot = 0; // disabled - qsaudit->items[item_offset].item_id = sub_inst->GetID(); - qsaudit->items[item_offset].charges = sub_inst->GetCharges(); - qsaudit->items[item_offset].aug_1 = sub_inst->GetAugmentItemID(1); - qsaudit->items[item_offset].aug_2 = sub_inst->GetAugmentItemID(2); - qsaudit->items[item_offset].aug_3 = sub_inst->GetAugmentItemID(3); - qsaudit->items[item_offset].aug_4 = sub_inst->GetAugmentItemID(4); - qsaudit->items[item_offset].aug_5 = sub_inst->GetAugmentItemID(5); - - if (finalizer) - ++qsaudit->char2_count; - else - ++qsaudit->char1_count; - } - } + qs_audit->char1_money.platinum = this->trade->pp; + qs_audit->char1_money.gold = this->trade->gp; + qs_audit->char1_money.silver = this->trade->sp; + qs_audit->char1_money.copper = this->trade->cp; } } @@ -541,22 +490,69 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) if (free_slot != INVALID_INDEX) { if (other->PutItemInInventory(free_slot, *inst, true)) { mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); + if (qs_log) { + QSTradeItems_Struct* detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = trade_slot; + detail->to_id = other->CharacterID(); + detail->to_slot = free_slot; + detail->item_id = inst->GetID(); + detail->charges = 1; + detail->aug_1 = inst->GetAugmentItemID(1); + detail->aug_2 = inst->GetAugmentItemID(2); + detail->aug_3 = inst->GetAugmentItemID(3); + detail->aug_4 = inst->GetAugmentItemID(4); + detail->aug_5 = inst->GetAugmentItemID(5); + + event_details->push_back(detail); + + if (finalizer) + qs_audit->char2_count += detail->charges; + else + qs_audit->char1_count += detail->charges; + + //for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) { + for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items + const ItemInst* bag_inst = inst->GetItem(sub_slot); + + if (bag_inst) { + detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = Inventory::CalcSlotId(trade_slot, sub_slot); + detail->to_id = other->CharacterID(); + detail->to_slot = Inventory::CalcSlotId(free_slot, sub_slot); + detail->item_id = bag_inst->GetID(); + detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges()); + detail->aug_1 = bag_inst->GetAugmentItemID(1); + detail->aug_2 = bag_inst->GetAugmentItemID(2); + detail->aug_3 = bag_inst->GetAugmentItemID(3); + detail->aug_4 = bag_inst->GetAugmentItemID(4); + detail->aug_5 = bag_inst->GetAugmentItemID(5); + + event_details->push_back(detail); + + if (finalizer) + qs_audit->char2_count += detail->charges; + else + qs_audit->char1_count += detail->charges; + } + } + } } else { mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName()); - PushItemOnCursor(*inst, true); } } else { mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID); - PushItemOnCursor(*inst, true); } } else { mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID); - PushItemOnCursor(*inst, true); } @@ -583,7 +579,6 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) if (partial_inst->GetID() != inst->GetID()) { _log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()"); - break; } @@ -606,6 +601,28 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) if (other->PutItemInInventory(partial_slot, *partial_inst, true)) { mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges())); + if (qs_log) { + QSTradeItems_Struct* detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = trade_slot; + detail->to_id = other->CharacterID(); + detail->to_slot = partial_slot; + detail->item_id = inst->GetID(); + detail->charges = (old_charges - inst->GetCharges()); + detail->aug_1 = 0; + detail->aug_2 = 0; + detail->aug_3 = 0; + detail->aug_4 = 0; + detail->aug_5 = 0; + + event_details->push_back(detail); + + if (finalizer) + qs_audit->char2_count += detail->charges; + else + qs_audit->char1_count += detail->charges; + } } else { mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.", @@ -613,13 +630,11 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) inst->SetCharges(old_charges); partial_inst->SetCharges(partial_charges); - break; } if (inst->GetCharges() == 0) { DeleteItemInInventory(trade_slot); - break; } } @@ -654,7 +669,6 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) if (inst->GetCharges() == 0) { DeleteItemInInventory(trade_slot); - break; } } @@ -675,22 +689,70 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) if (free_slot != INVALID_INDEX) { if (other->PutItemInInventory(free_slot, *inst, true)) { mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); + if (qs_log) { + QSTradeItems_Struct* detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = trade_slot; + detail->to_id = other->CharacterID(); + detail->to_slot = free_slot; + detail->item_id = inst->GetID(); + detail->charges = (!inst->IsStackable() ? 1 : inst->GetCharges()); + detail->aug_1 = inst->GetAugmentItemID(1); + detail->aug_2 = inst->GetAugmentItemID(2); + detail->aug_3 = inst->GetAugmentItemID(3); + detail->aug_4 = inst->GetAugmentItemID(4); + detail->aug_5 = inst->GetAugmentItemID(5); + + event_details->push_back(detail); + + if (finalizer) + qs_audit->char2_count += detail->charges; + else + qs_audit->char1_count += detail->charges; + + // 'step 3' should never really see containers..but, just in case... + //for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) { + for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items + const ItemInst* bag_inst = inst->GetItem(sub_slot); + + if (bag_inst) { + detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = trade_slot; + detail->to_id = other->CharacterID(); + detail->to_slot = free_slot; + detail->item_id = bag_inst->GetID(); + detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges()); + detail->aug_1 = bag_inst->GetAugmentItemID(1); + detail->aug_2 = bag_inst->GetAugmentItemID(2); + detail->aug_3 = bag_inst->GetAugmentItemID(3); + detail->aug_4 = bag_inst->GetAugmentItemID(4); + detail->aug_5 = bag_inst->GetAugmentItemID(5); + + event_details->push_back(detail); + + if (finalizer) + qs_audit->char2_count += detail->charges; + else + qs_audit->char1_count += detail->charges; + } + } + } } else { mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName()); - PushItemOnCursor(*inst, true); } } else { mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID); - PushItemOnCursor(*inst, true); } } else { mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID); - PushItemOnCursor(*inst, true); } @@ -701,65 +763,73 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) //Do not reset the trade here, done by the caller. } } - - // trading with npc doesn't require Inventory::FindFreeSlotForTradeItem() rework else if(tradingWith && tradingWith->IsNPC()) { - QSPlayerLogHandin_Struct* qsaudit = nullptr; - bool QSPLH = false; + QSPlayerLogHandin_Struct* qs_audit = nullptr; + bool qs_log = false; // QS code - if(qspack && RuleB(QueryServ, PlayerLogTrades)) { + if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) { // Currently provides only basic functionality. Calling method will also // need to be modified before item returns and rewards can be logged. -U - qsaudit = (QSPlayerLogHandin_Struct*) qspack->pBuffer; - QSPLH = true; + qs_audit = (QSPlayerLogHandin_Struct*)event_entry; + qs_log = true; - qsaudit->quest_id = 0; - qsaudit->char_id = character_id; - qsaudit->char_money.platinum = trade->pp; - qsaudit->char_money.gold = trade->gp; - qsaudit->char_money.silver = trade->sp; - qsaudit->char_money.copper = trade->cp; - qsaudit->char_count = 0; - qsaudit->npc_id = tradingWith->GetNPCTypeID(); - qsaudit->npc_money.platinum = 0; - qsaudit->npc_money.gold = 0; - qsaudit->npc_money.silver = 0; - qsaudit->npc_money.copper = 0; - qsaudit->npc_count = 0; + qs_audit->quest_id = 0; + qs_audit->char_id = character_id; + qs_audit->char_money.platinum = trade->pp; + qs_audit->char_money.gold = trade->gp; + qs_audit->char_money.silver = trade->sp; + qs_audit->char_money.copper = trade->cp; + qs_audit->char_count = 0; + qs_audit->npc_id = tradingWith->GetNPCTypeID(); + qs_audit->npc_money.platinum = 0; + qs_audit->npc_money.gold = 0; + qs_audit->npc_money.silver = 0; + qs_audit->npc_money.copper = 0; + qs_audit->npc_count = 0; } - if(QSPLH) { // This can be incoporated below when revisions are made -U - for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) { - const ItemInst* trade_inst = m_inv[slot_id]; + if(qs_log) { // This can be incorporated below when revisions are made -U + for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) { + const ItemInst* trade_inst = m_inv[trade_slot]; if(trade_inst) { - strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN"); + QSHandinItems_Struct* detail = new QSHandinItems_Struct; - qsaudit->items[qsaudit->char_count].char_slot = slot_id; - qsaudit->items[qsaudit->char_count].item_id = trade_inst->GetID(); - qsaudit->items[qsaudit->char_count].charges = trade_inst->GetCharges(); - qsaudit->items[qsaudit->char_count].aug_1 = trade_inst->GetAugmentItemID(1); - qsaudit->items[qsaudit->char_count].aug_2 = trade_inst->GetAugmentItemID(2); - qsaudit->items[qsaudit->char_count].aug_3 = trade_inst->GetAugmentItemID(3); - qsaudit->items[qsaudit->char_count].aug_4 = trade_inst->GetAugmentItemID(4); - qsaudit->items[qsaudit->char_count++].aug_5 = trade_inst->GetAugmentItemID(5); + strcpy(detail->action_type, "HANDIN"); + + detail->char_slot = trade_slot; + detail->item_id = trade_inst->GetID(); + detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges()); + detail->aug_1 = trade_inst->GetAugmentItemID(1); + detail->aug_2 = trade_inst->GetAugmentItemID(2); + detail->aug_3 = trade_inst->GetAugmentItemID(3); + detail->aug_4 = trade_inst->GetAugmentItemID(4); + detail->aug_5 = trade_inst->GetAugmentItemID(5); + + event_details->push_back(detail); + qs_audit->char_count += detail->charges; if(trade_inst->IsType(ItemClassContainer)) { - for(uint8 bag_idx = SUB_BEGIN; bag_idx < trade_inst->GetItem()->BagSlots; bag_idx++) { - const ItemInst* trade_baginst = trade_inst->GetItem(bag_idx); + for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) { + const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot); if(trade_baginst) { - strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN"); + detail = new QSHandinItems_Struct; - qsaudit->items[qsaudit->char_count].char_slot = Inventory::CalcSlotId(slot_id, bag_idx); - qsaudit->items[qsaudit->char_count].item_id = trade_baginst->GetID(); - qsaudit->items[qsaudit->char_count].charges = trade_baginst->GetCharges(); - qsaudit->items[qsaudit->char_count].aug_1 = trade_baginst->GetAugmentItemID(1); - qsaudit->items[qsaudit->char_count].aug_2 = trade_baginst->GetAugmentItemID(2); - qsaudit->items[qsaudit->char_count].aug_3 = trade_baginst->GetAugmentItemID(3); - qsaudit->items[qsaudit->char_count].aug_4 = trade_baginst->GetAugmentItemID(4); - qsaudit->items[qsaudit->char_count++].aug_5 = trade_baginst->GetAugmentItemID(5); + strcpy(detail->action_type, "HANDIN"); + + detail->char_slot = Inventory::CalcSlotId(trade_slot, sub_slot); + detail->item_id = trade_baginst->GetID(); + detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges()); + detail->aug_1 = trade_baginst->GetAugmentItemID(1); + detail->aug_2 = trade_baginst->GetAugmentItemID(2); + detail->aug_3 = trade_baginst->GetAugmentItemID(3); + detail->aug_4 = trade_baginst->GetAugmentItemID(4); + detail->aug_5 = trade_baginst->GetAugmentItemID(5); + + event_details->push_back(detail); + qs_audit->char_count += detail->charges; } } } From 18a4f831be630adca360763dfbc302f5d3d07767 Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 26 Aug 2014 06:37:40 -0400 Subject: [PATCH 54/57] Tweaked QS code for Client::FinishTrade() and QueryServ handlers. --- changelog.txt | 6 ++++++ common/servertalk.h | 2 ++ queryserv/database.cpp | 12 ++++++------ queryserv/database.h | 4 ++-- queryserv/worldserver.cpp | 6 ++---- zone/client_packet.cpp | 6 ++++-- zone/trading.cpp | 20 ++++++++++++++++++++ 7 files changed, 42 insertions(+), 14 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9172332d9..98e1f0606 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 08/26/2014 == +Uleat: Implemented 'Smart' Player Trade transfers. Trades are processed by containers, stackables and then all remaining. QueryServ logs have been updated to match these transactions. +Note: QueryServ logs previously listed 'Items' on the main entry table. This indicated the number of slots affected and not the actual number of items. +This field now indicates the actual number of items transferred. For non-stackable, the value is '1' and stackable is the number of charges. A _detail_count +property has been added to both 'Trade' and 'Handin' structs to indicate the number of details recorded..though, not tracked..it could be added. + == 08/24/2014 == Uleat: Fix (attempted) for zone crashes related to zone shut-down. This change disables all Mob AI and disables/deletes all Mob timers once Zone::ShutDown() is called. More areas will be addressed as reports come in. Note: Perl and Lua quests tested to work..please post any aberrant behavior. (I finally set my spell-check to US English...) diff --git a/common/servertalk.h b/common/servertalk.h index 6d1a83a84..5337b6b1d 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -1118,6 +1118,7 @@ struct QSPlayerLogTrade_Struct { uint32 char2_id; MoneyUpdate_Struct char2_money; uint16 char2_count; + uint16 _detail_count; QSTradeItems_Struct items[0]; }; @@ -1141,6 +1142,7 @@ struct QSPlayerLogHandin_Struct { uint32 npc_id; MoneyUpdate_Struct npc_money; uint16 npc_count; + uint16 _detail_count; QSHandinItems_Struct items[0]; }; diff --git a/queryserv/database.cpp b/queryserv/database.cpp index 4b94f215b..cfc4a8892 100644 --- a/queryserv/database.cpp +++ b/queryserv/database.cpp @@ -119,7 +119,7 @@ void Database::AddSpeech(const char* from, const char* to, const char* message, safe_delete_array(S3); } -void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) { +void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount) { char errbuf[MYSQL_ERRMSG_SIZE]; char* query = 0; @@ -134,8 +134,8 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) { _log(QUERYSERV__ERROR, "%s", query); } - if(Items > 0) { - for(int i = 0; i < Items; i++) { + if(DetailCount > 0) { + for(int i = 0; i < DetailCount; 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'", @@ -149,7 +149,7 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) { } } -void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) { +void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount) { char errbuf[MYSQL_ERRMSG_SIZE]; char* query = 0; uint32 lastid = 0; @@ -163,8 +163,8 @@ void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) { _log(QUERYSERV__ERROR, "%s", query); } - if(Items > 0) { - for(int i = 0; i < Items; i++) { + if(DetailCount > 0) { + for(int i = 0; i < DetailCount; 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'", diff --git a/queryserv/database.h b/queryserv/database.h index ac002a0b5..a25d91611 100644 --- a/queryserv/database.h +++ b/queryserv/database.h @@ -43,8 +43,8 @@ public: ~Database(); void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type); - void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items); - void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items); + void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount); + void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount); void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members); void LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items); void LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items); diff --git a/queryserv/worldserver.cpp b/queryserv/worldserver.cpp index 154db3a07..fc87929ca 100644 --- a/queryserv/worldserver.cpp +++ b/queryserv/worldserver.cpp @@ -80,14 +80,12 @@ void WorldServer::Process() } case ServerOP_QSPlayerLogTrades: { QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)pack->pBuffer; - uint32 Items = QS->char1_count + QS->char2_count; - database.LogPlayerTrade(QS, Items); + database.LogPlayerTrade(QS, QS->_detail_count); break; } case ServerOP_QSPlayerLogHandins: { QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)pack->pBuffer; - uint32 Items = QS->char_count + QS->npc_count; - database.LogPlayerHandin(QS, Items); + database.LogPlayerHandin(QS, QS->_detail_count); break; } case ServerOP_QSPlayerLogNPCKills: { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8d39f815a..76c873711 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4898,8 +4898,9 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) this->FinishTrade(other, true, &event_entry, &event_details); other->FinishTrade(this, false, &event_entry, &event_details); - ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_details.size())); + event_entry._detail_count = event_details.size(); + ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_entry._detail_count)); QSPlayerLogTrade_Struct* qs_buf = (QSPlayerLogTrade_Struct*)qs_pack->pBuffer; memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogTrade_Struct)); @@ -4951,8 +4952,9 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) FinishTrade(with->CastToNPC(), false, &event_entry, &event_details); - ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_details.size())); + event_entry._detail_count = event_details.size(); + ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_entry._detail_count)); QSPlayerLogHandin_Struct* qs_buf = (QSPlayerLogHandin_Struct*)qs_pack->pBuffer; memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogHandin_Struct)); diff --git a/zone/trading.cpp b/zone/trading.cpp index 88b277651..23d8d77af 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -656,6 +656,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize)) continue; + int16 old_charges = inst->GetCharges(); + if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) { int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize; @@ -667,6 +669,24 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st inst->SetCharges(0); } + if (qs_log) { + QSTradeItems_Struct* detail = new QSTradeItems_Struct; + + detail->from_id = this->character_id; + detail->from_slot = trade_slot; + detail->to_id = this->character_id; + detail->to_slot = bias_slot; + detail->item_id = inst->GetID(); + detail->charges = (old_charges - inst->GetCharges()); + detail->aug_1 = 0; + detail->aug_2 = 0; + detail->aug_3 = 0; + detail->aug_4 = 0; + detail->aug_5 = 0; + + event_details->push_back(detail); + } + if (inst->GetCharges() == 0) { DeleteItemInInventory(trade_slot); break; From dedd1fc70df5162653fc3417e3e27a7ec1001ac4 Mon Sep 17 00:00:00 2001 From: akkadius Date: Wed, 27 Aug 2014 14:26:36 -0500 Subject: [PATCH 55/57] NPC::ModifyNPCStat function bloat cleanup --- zone/npc.cpp | 283 ++++++++------------------------------------------- 1 file changed, 40 insertions(+), 243 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index f70c1e847..151852a2b 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -1787,252 +1787,49 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue) { std::string id = identifier; std::string val = newValue; - for(int i = 0; i < id.length(); ++i) - { + for(int i = 0; i < id.length(); ++i) { id[i] = std::tolower(id[i]); } - if(id == "ac") - { - AC = atoi(val.c_str()); - return; - } - - if(id == "str") - { - STR = atoi(val.c_str()); - return; - } - - if(id == "sta") - { - STA = atoi(val.c_str()); - return; - } - - if(id == "agi") - { - AGI = atoi(val.c_str()); - return; - } - - if(id == "dex") - { - DEX = atoi(val.c_str()); - return; - } - - if(id == "wis") - { - WIS = atoi(val.c_str()); - CalcMaxMana(); - return; - } - - if(id == "int" || id == "_int") - { - INT = atoi(val.c_str()); - CalcMaxMana(); - return; - } - - if(id == "cha") - { - CHA = atoi(val.c_str()); - return; - } - - if(id == "max_hp") - { - base_hp = atoi(val.c_str()); - CalcMaxHP(); - if(cur_hp > max_hp) - cur_hp = max_hp; - return; - } - - if(id == "max_mana") - { - npc_mana = atoi(val.c_str()); - CalcMaxMana(); - if(cur_mana > max_mana) - cur_mana = max_mana; - return; - } - - if(id == "mr") - { - MR = atoi(val.c_str()); - return; - } - - if(id == "fr") - { - FR = atoi(val.c_str()); - return; - } - - if(id == "cr") - { - CR = atoi(val.c_str()); - return; - } - - if(id == "pr") - { - PR = atoi(val.c_str()); - return; - } - - if(id == "dr") - { - DR = atoi(val.c_str()); - return; - } - - if(id == "PhR") - { - PhR = atoi(val.c_str()); - return; - } - - if(id == "runspeed") - { - runspeed = (float)atof(val.c_str()); - CalcBonuses(); - return; - } - - if(id == "special_attacks") - { - //Added reset flag. - NPCSpecialAttacks(val.c_str(), 0, 1); - return; - } - - if(id == "attack_speed") - { - attack_speed = (float)atof(val.c_str()); - CalcBonuses(); - return; - } - - if(id == "atk") - { - ATK = atoi(val.c_str()); - return; - } - - if(id == "accuracy") - { - accuracy_rating = atoi(val.c_str()); - return; - } - - if(id == "avoidance") - { - avoidance_rating = atoi(val.c_str()); - return; - } - - if(id == "trackable") - { - trackable = atoi(val.c_str()); - return; - } - - if(id == "min_hit") - { - min_dmg = atoi(val.c_str()); - return; - } - - if(id == "max_hit") - { - max_dmg = atoi(val.c_str()); - return; - } - - if(id == "attack_count") - { - attack_count = atoi(val.c_str()); - return; - } - - if(id == "see_invis") - { - see_invis = atoi(val.c_str()); - return; - } - - if(id == "see_invis_undead") - { - see_invis_undead = atoi(val.c_str()); - return; - } - - if(id == "see_hide") - { - see_hide = atoi(val.c_str()); - return; - } - - if(id == "see_improved_hide") - { - see_improved_hide = atoi(val.c_str()); - return; - } - - if(id == "hp_regen") - { - hp_regen = atoi(val.c_str()); - return; - } - - if(id == "mana_regen") - { - mana_regen = atoi(val.c_str()); - return; - } - - if(id == "level") - { - SetLevel(atoi(val.c_str())); - return; - } - - if(id == "aggro") - { - pAggroRange = atof(val.c_str()); - return; - } - - if(id == "assist") - { - pAssistRange = atof(val.c_str()); - return; - } - - if(id == "slow_mitigation") - { - slow_mitigation = atoi(val.c_str()); - return; - } - if(id == "loottable_id") - { - loottable_id = atof(val.c_str()); - return; - } - if(id == "healscale") - { - healscale = atof(val.c_str()); - return; - } - if(id == "spellscale") - { - spellscale = atof(val.c_str()); - return; - } + if(id == "ac") { AC = atoi(val.c_str()); return; } + else if(id == "str") { STR = atoi(val.c_str()); return; } + else if(id == "sta") { STA = atoi(val.c_str()); return; } + else if(id == "agi") { AGI = atoi(val.c_str()); return; } + else if(id == "dex") { DEX = atoi(val.c_str()); return; } + else if(id == "wis") { WIS = atoi(val.c_str()); CalcMaxMana(); return; } + else if(id == "int" || id == "_int") { INT = atoi(val.c_str()); CalcMaxMana(); return; } + else if(id == "cha") { CHA = atoi(val.c_str()); return; } + else if(id == "max_hp") { base_hp = atoi(val.c_str()); CalcMaxHP(); if (cur_hp > max_hp) { cur_hp = max_hp; } return; } + else if(id == "max_mana") { npc_mana = atoi(val.c_str()); CalcMaxMana(); if (cur_mana > max_mana){ cur_mana = max_mana; } return; } + else if(id == "mr") { MR = atoi(val.c_str()); return; } + else if(id == "fr") { FR = atoi(val.c_str()); return; } + else if(id == "cr") { CR = atoi(val.c_str()); return; } + else if(id == "pr") { PR = atoi(val.c_str()); return; } + else if(id == "dr") { DR = atoi(val.c_str()); return; } + else if(id == "PhR") { PhR = atoi(val.c_str()); return; } + else if(id == "runspeed") { runspeed = (float)atof(val.c_str()); CalcBonuses(); return; } + else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; } + else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; } + else if(id == "atk") { ATK = atoi(val.c_str()); return; } + else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; } + else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; } + else if(id == "trackable") { trackable = atoi(val.c_str()); return; } + else if(id == "min_hit") { min_dmg = atoi(val.c_str()); return; } + else if(id == "max_hit") { max_dmg = atoi(val.c_str()); return; } + else if(id == "attack_count") { attack_count = atoi(val.c_str()); return; } + else if(id == "see_invis") { see_invis = atoi(val.c_str()); return; } + else if(id == "see_invis_undead") { see_invis_undead = atoi(val.c_str()); return; } + else if(id == "see_hide") { see_hide = atoi(val.c_str()); return; } + else if(id == "see_improved_hide") { see_improved_hide = atoi(val.c_str()); return; } + else if(id == "hp_regen") { hp_regen = atoi(val.c_str()); return; } + else if(id == "mana_regen") { mana_regen = atoi(val.c_str()); return; } + else if(id == "level") { SetLevel(atoi(val.c_str())); return; } + else if(id == "aggro") { pAggroRange = atof(val.c_str()); return; } + else if(id == "assist") { pAssistRange = atof(val.c_str()); return; } + else if(id == "slow_mitigation") { slow_mitigation = atoi(val.c_str()); return; } + else if(id == "loottable_id") { loottable_id = atof(val.c_str()); return; } + else if(id == "healscale") { healscale = atof(val.c_str()); return; } + else if(id == "spellscale") { spellscale = atof(val.c_str()); return; } } void NPC::LevelScale() { From 9041891557d685b9da86e32bf9c71ff6f8bc51a4 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Wed, 27 Aug 2014 22:57:03 -0700 Subject: [PATCH 56/57] Fixed crash on expire mail success, messages where switched accidentally --- ucs/database.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ucs/database.cpp b/ucs/database.cpp index d3c44174c..8eb8746b3 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -523,9 +523,10 @@ void Database::ExpireMail() { time(nullptr) - RuleI(Mail, ExpireTrash)); results = QueryDatabase(query); if(!results.Success()) - _log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected()); + _log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str()); else - _log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str()); + _log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected()); + } // Expire Read From 9d6dc47cf4d71ea6c12c838dc81f75c458f0d79a Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 28 Aug 2014 02:15:37 -0400 Subject: [PATCH 57/57] Fix crash with MySQLRequestResult::ErrorMessage() --- common/mysql_request_result.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/mysql_request_result.h b/common/mysql_request_result.h index cd561be56..ab84eeb18 100644 --- a/common/mysql_request_result.h +++ b/common/mysql_request_result.h @@ -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;}