Skip to content

Commit d2018a7

Browse files
authored
Merge pull request LandSandBoat#7305 from beasty-lsb-forked/player_item_logging
[core/sql] Feature: Common Player Transaction Logging/Audit
2 parents d87600e + ac72a3e commit d2018a7

File tree

8 files changed

+224
-0
lines changed

8 files changed

+224
-0
lines changed

settings/default/map.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ xi.settings.map =
274274
AUDIT_UNITY = false,
275275
AUDIT_PARTY = false,
276276

277+
-- Player Item Transaction Logging (Default: Off)
278+
-- Logs player item transactions to the database for persistence.
279+
AUDIT_PLAYER_TRADES = false,
280+
AUDIT_PLAYER_BAZAAR = false,
281+
AUDIT_PLAYER_DBOX = false,
282+
AUDIT_PLAYER_VENDOR = false,
283+
277284
-- Seconds between healing ticks. Default is 10
278285
HEALING_TICK_DELAY = 10,
279286

sql/audit_bazaar.sql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
2+
3+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
4+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
5+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
6+
/*!40101 SET NAMES utf8 */;
7+
8+
--
9+
-- Table structure of `audit_bazaar`
10+
--
11+
12+
CREATE TABLE IF NOT EXISTS `audit_bazaar` (
13+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
14+
`itemid` smallint(5) unsigned NOT NULL DEFAULT '0',
15+
`quantity` int(10) unsigned NOT NULL DEFAULT '0',
16+
`seller` int(10) unsigned NOT NULL DEFAULT '0',
17+
`seller_name` varchar(15) DEFAULT NULL,
18+
`purchaser` int(10) unsigned NOT NULL DEFAULT '0',
19+
`purchaser_name` varchar(15) DEFAULT NULL,
20+
`price` int(10) unsigned NOT NULL DEFAULT '0',
21+
`date` int(10) unsigned NOT NULL DEFAULT '0',
22+
PRIMARY KEY (`id`),
23+
KEY `itemid` (`itemid`),
24+
KEY `charid` (`seller`)
25+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
26+
27+
--
28+
-- Table contents of `audit_bazaar`
29+
--

sql/audit_dbox.sql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
2+
3+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
4+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
5+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
6+
/*!40101 SET NAMES utf8 */;
7+
8+
--
9+
-- Table structure of `audit_dbox`
10+
--
11+
12+
CREATE TABLE IF NOT EXISTS `audit_dbox` (
13+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
14+
`itemid` smallint(5) unsigned NOT NULL DEFAULT '0',
15+
`quantity` int(10) unsigned NOT NULL DEFAULT '0',
16+
`sender` int(10) unsigned NOT NULL DEFAULT '0',
17+
`sender_name` varchar(15) DEFAULT NULL,
18+
`receiver` int(10) unsigned NOT NULL DEFAULT '0',
19+
`receiver_name` varchar(15) DEFAULT NULL,
20+
`price`int(10) unsigned NOT NULL DEFAULT '0',
21+
`date` int(10) unsigned NOT NULL DEFAULT '0',
22+
PRIMARY KEY (`id`),
23+
KEY `itemid` (`itemid`),
24+
KEY `charid` (`sender`)
25+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
26+
27+
--
28+
-- Table contents of `audit_dbox`
29+
--

sql/audit_trade.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
2+
3+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
4+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
5+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
6+
/*!40101 SET NAMES utf8 */;
7+
8+
--
9+
-- Table structure of `audit_trade`
10+
--
11+
12+
CREATE TABLE IF NOT EXISTS `audit_trade` (
13+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
14+
`itemid` smallint(5) unsigned NOT NULL DEFAULT '0',
15+
`quantity` int(10) unsigned NOT NULL DEFAULT '0',
16+
`sender` int(10) unsigned NOT NULL DEFAULT '0',
17+
`sender_name` varchar(15) DEFAULT NULL,
18+
`receiver` int(10) unsigned NOT NULL DEFAULT '0',
19+
`receiver_name` varchar(15) DEFAULT NULL,
20+
`date` int(10) unsigned NOT NULL DEFAULT '0',
21+
PRIMARY KEY (`id`),
22+
KEY `itemid` (`itemid`),
23+
KEY `charid` (`sender`)
24+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
25+
26+
--
27+
-- Table contents of `audit_trade`
28+
--

sql/audit_vendor.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
2+
3+
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
4+
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
5+
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
6+
/*!40101 SET NAMES utf8 */;
7+
8+
--
9+
-- Table structure of `audit_vendor`
10+
--
11+
12+
CREATE TABLE IF NOT EXISTS `audit_vendor` (
13+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
14+
`itemid` smallint(5) unsigned NOT NULL DEFAULT '0',
15+
`quantity` int(10) unsigned NOT NULL DEFAULT '0',
16+
`seller` int(10) unsigned NOT NULL DEFAULT '0',
17+
`seller_name` varchar(15) DEFAULT NULL,
18+
`baseprice` int(10) unsigned NOT NULL DEFAULT '0',
19+
`totalprice` int(10) unsigned NOT NULL DEFAULT '0',
20+
`date` int(10) unsigned NOT NULL DEFAULT '0',
21+
PRIMARY KEY (`id`),
22+
KEY `itemid` (`itemid`),
23+
KEY `charid` (`seller`)
24+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
25+
26+
--
27+
-- Table contents of `audit_vendor`
28+
--

src/map/packet_system.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,25 @@ void SmallPacket0x034(MapSession* const PSession, CCharEntity* const PChar, CBas
17941794
PItem->setReserve(quantity + PItem->getReserve());
17951795
PChar->UContainer->SetItem(tradeSlotID, PItem);
17961796
}
1797+
1798+
if (settings::get<bool>("map.AUDIT_PLAYER_TRADES"))
1799+
{
1800+
Async::getInstance()->submit(
1801+
[itemID = PItem->getID(),
1802+
quantity = quantity,
1803+
sender = PChar->id,
1804+
sender_name = PChar->getName(),
1805+
receiver = PTarget->id,
1806+
receiver_name = PTarget->getName(),
1807+
date = static_cast<uint32>(time(nullptr))]()
1808+
{
1809+
const auto query = "INSERT INTO audit_trade(itemid, quantity, sender, sender_name, receiver, receiver_name, date) VALUES (?, ?, ?, ?, ?, ?, ?)";
1810+
if (!db::preparedStmt(query, itemID, quantity, sender, sender_name, receiver, receiver_name, date))
1811+
{
1812+
ShowErrorFmt("Failed to log trade transaction (item: {}, quantity: {}, sender: {}, receiver: {}, date: {})", itemID, quantity, sender, receiver, date);
1813+
}
1814+
});
1815+
}
17971816
}
17981817
else
17991818
{
@@ -1880,6 +1899,25 @@ void SmallPacket0x036(MapSession* const PSession, CCharEntity* const PChar, CBas
18801899
return;
18811900
}
18821901

1902+
if (settings::get<bool>("map.AUDIT_PLAYER_TRADES"))
1903+
{
1904+
Async::getInstance()->submit(
1905+
[itemID = PItem->getID(),
1906+
quantity = Quantity,
1907+
sender = PChar->id,
1908+
sender_name = PChar->getName(),
1909+
receiver = PNpc->id,
1910+
receiver_name = PNpc->getName(),
1911+
date = static_cast<uint32>(time(nullptr))]()
1912+
{
1913+
const auto query = "INSERT INTO audit_trade(itemid, quantity, sender, sender_name, receiver, receiver_name, date) VALUES (?, ?, ?, ?, ?, ?, ?)";
1914+
if (!db::preparedStmt(query, itemID, quantity, sender, sender_name, receiver, receiver_name, date))
1915+
{
1916+
ShowErrorFmt("Failed to log trade transaction (item: {}, quantity: {}, sender: {}, receiver: {}, date: {})", itemID, quantity, sender, receiver, date);
1917+
}
1918+
});
1919+
}
1920+
18831921
PItem->setReserve(Quantity);
18841922
PChar->TradeContainer->setItem(slotID, PItem->getID(), invSlotID, Quantity, PItem);
18851923
}
@@ -4116,6 +4154,25 @@ void SmallPacket0x085(MapSession* const PSession, CCharEntity* const PChar, CBas
41164154

41174155
const auto cost = quantity * PItem->getBasePrice();
41184156

4157+
if (settings::get<bool>("map.AUDIT_PLAYER_VENDOR"))
4158+
{
4159+
Async::getInstance()->submit(
4160+
[itemid = PItem->getID(),
4161+
quantity = quantity,
4162+
seller = PChar->id,
4163+
seller_name = PChar->getName(),
4164+
baseprice = PItem->getBasePrice(),
4165+
totalprice = cost,
4166+
time = static_cast<uint32>(time(nullptr))]()
4167+
{
4168+
const auto query = "INSERT INTO audit_vendor(itemid, quantity, seller, seller_name, baseprice, totalprice, date) VALUES (?, ?, ?, ?, ?, ?, ?)";
4169+
if (!db::preparedStmt(query, itemid, quantity, seller, seller_name, baseprice, totalprice, time))
4170+
{
4171+
ShowErrorFmt("Failed to log vendor sale (item: {}, quantity: {}, seller: {}, totalprice: {}, time: {})", itemid, quantity, seller, totalprice, time);
4172+
}
4173+
});
4174+
}
4175+
41194176
charutils::UpdateItem(PChar, LOC_INVENTORY, 0, cost);
41204177
charutils::UpdateItem(PChar, LOC_INVENTORY, slotID, -(int32)quantity);
41214178
ShowInfo("SmallPacket0x085: Player '%s' sold %u of itemID %u (Total: %u gil) [to VENDOR] ", PChar->getName(), quantity, itemID, cost);
@@ -7135,6 +7192,26 @@ void SmallPacket0x106(MapSession* const PSession, CCharEntity* const PChar, CBas
71357192
return;
71367193
}
71377194

7195+
if (settings::get<bool>("map.AUDIT_PLAYER_BAZAAR"))
7196+
{
7197+
Async::getInstance()->submit(
7198+
[itemID = PItem->getID(),
7199+
quantity = Quantity,
7200+
sellerID = PTarget->id,
7201+
sellerName = PTarget->getName(),
7202+
purchaserID = PChar->id,
7203+
purchaserName = PChar->getName(),
7204+
price = PriceWithTax,
7205+
date = static_cast<uint32>(time(nullptr))]
7206+
{
7207+
const auto query = "INSERT INTO audit_bazaar(itemid, quantity, seller, seller_name, purchaser, purchaser_name, price, date) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
7208+
if (!db::preparedStmt(query, itemID, quantity, sellerID, sellerName, purchaserID, purchaserName, price, date))
7209+
{
7210+
ShowErrorFmt("Failed to log bazaar purchase (ItemID: {}, Quantity: {}, Seller: {}, Purchaser: {}, Price: {})", itemID, quantity, sellerName, purchaserName, price);
7211+
}
7212+
});
7213+
}
7214+
71387215
charutils::UpdateItem(PChar, LOC_INVENTORY, 0, -(int32)PriceWithTax);
71397216
charutils::UpdateItem(PTarget, LOC_INVENTORY, 0, Price);
71407217

src/map/utils/dboxutils.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
===========================================================================
2020
*/
2121

22+
#include "common/async.h"
23+
2224
#include "dboxutils.h"
2325

2426
#include "common/database.h"
@@ -525,6 +527,26 @@ void dboxutils::SendNewItems(CCharEntity* PChar, uint8 action, uint8 boxtype, ui
525527
db::preparedStmt("UPDATE delivery_box SET received = 1 WHERE senderid = ? AND charid = ? AND box = 2 AND received = 0 AND quantity = ? AND sent = 1 AND itemid = ? LIMIT 1",
526528
PChar->id, senderID, PItem->getQuantity(), PItem->getID());
527529

530+
if (settings::get<bool>("map.AUDIT_PLAYER_DBOX"))
531+
{
532+
Async::getInstance()->submit(
533+
[itemid = PItem->getID(),
534+
quantity = PItem->getQuantity(),
535+
sender = senderID,
536+
sender_name = PItem->getSender(),
537+
receiver = PChar->id,
538+
receiver_name = PChar->getName(),
539+
date = static_cast<uint32>(time(nullptr))]()
540+
{
541+
const auto query = "INSERT INTO audit_dbox(itemid, quantity, sender, sender_name, receiver, receiver_name, date) VALUES (?, ?, ?, ?, ?, ?, ?)";
542+
if (!db::preparedStmt(query, itemid, quantity, sender, sender_name, receiver, receiver_name, date))
543+
{
544+
ShowErrorFmt("Failed to log delivery box transaction (item: {}, quantity: {}, sender: {}, receiver: {}, date: {})", itemid, quantity, sender, receiver, date);
545+
}
546+
}
547+
);
548+
}
549+
528550
const auto rset = db::preparedStmt("SELECT slot FROM delivery_box WHERE charid = ? AND box = 1 AND slot > 7 ORDER BY slot ASC", PChar->id);
529551
FOR_DB_SINGLE_RESULT(rset)
530552
{

tools/dbtool.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ def load_into_dict(filename, settings):
185185
"accounts_banned.sql",
186186
"auction_house_items.sql",
187187
"auction_house.sql",
188+
"audit_bazaar.sql",
189+
"audit_dbox.sql",
190+
"audit_trade.sql",
191+
"audit_vendor.sql",
188192
"char_blacklist.sql",
189193
"char_chocobos.sql",
190194
"char_effects.sql",

0 commit comments

Comments
 (0)