mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-18 18:52:48 +00:00
feat: contraband list with flagging and optional removal
Staff list contraband items on a new dashboard page (item search, reason, flag or flag and remove; contraband_manage to edit, reports_view to see). World servers check every inventory when a character loads and every item a player receives: each find is an economy flag of the new kind Contraband, shown with the other flags and in the character's related data. Items marked for removal are taken away, with a character snapshot kept first so they can be given back, an audit entry and a mail or chat message telling the player why. Staff are skipped unless contraband_ignore_staff is off. Worlds reload the list when it changes (RELOAD_CONTRABAND, added at the end of ePlayerAction). Fixes #1563 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
#include "ILiveOps.h"
|
||||
#include "IFeaturedProperties.h"
|
||||
#include "IMessageCaptures.h"
|
||||
#include "IContraband.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define DLU_SQL_TRY_CATCH_RETHROW(x) do { try { x; } catch (std::exception& ex) { LOG("SQL Error: %s", ex.what()); throw; } } while(0)
|
||||
@@ -60,7 +61,7 @@ class GameDatabase :
|
||||
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
||||
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
||||
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList,
|
||||
public IBehaviors, public IUgcModularBuild, public IAuditLog, public IDashboardStats, public IAccountEmails, public IDashboardMaintenance, public IEconomyLedger, public IDashboardAdmin, public IServerConfig, public IScheduledTasks, public ICharacterSnapshots, public IAccountNotes, public IServerHealth, public IRelatedData, public IChatLog, public IAccountStrikes, public ISlashCommands, public IModeration, public IServerOperations, public IPlayerPositions, public IAiSuggestions, public ILiveOps, public IFeaturedProperties, public IMessageCaptures {
|
||||
public IBehaviors, public IUgcModularBuild, public IAuditLog, public IDashboardStats, public IAccountEmails, public IDashboardMaintenance, public IEconomyLedger, public IDashboardAdmin, public IServerConfig, public IScheduledTasks, public ICharacterSnapshots, public IAccountNotes, public IServerHealth, public IRelatedData, public IChatLog, public IAccountStrikes, public ISlashCommands, public IModeration, public IServerOperations, public IPlayerPositions, public IAiSuggestions, public ILiveOps, public IFeaturedProperties, public IMessageCaptures, public IContraband {
|
||||
public:
|
||||
virtual ~GameDatabase() = default;
|
||||
// TODO: These should be made private.
|
||||
|
||||
40
dDatabase/GameDatabase/ITables/IContraband.h
Normal file
40
dDatabase/GameDatabase/ITables/IContraband.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef __ICONTRABAND__H__
|
||||
#define __ICONTRABAND__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dCommonVars.h"
|
||||
|
||||
/**
|
||||
* Contraband: items staff don't want players to have (issue #1563), edited on the dashboard. World servers check a
|
||||
* character's items against the list when it loads and when items are added, and flag (an economy flag of kind
|
||||
* CONTRABAND) or also remove them.
|
||||
*/
|
||||
class IContraband {
|
||||
public:
|
||||
enum class eContrabandAction : uint8_t {
|
||||
FLAG = 0, // only flag the character
|
||||
REMOVE = 1 // flag the character and remove the item
|
||||
};
|
||||
|
||||
struct ContrabandItem {
|
||||
LOT lot{};
|
||||
std::string reason;
|
||||
eContrabandAction action{};
|
||||
std::string addedBy;
|
||||
int64_t addedAt{};
|
||||
};
|
||||
|
||||
// Every listed item, by LOT
|
||||
virtual std::vector<ContrabandItem> GetContrabandItems() = 0;
|
||||
|
||||
// Insert or replace the row of item.lot
|
||||
virtual void SetContrabandItem(const ContrabandItem& item) = 0;
|
||||
|
||||
// Whether there was a row to delete
|
||||
virtual bool DeleteContrabandItem(LOT lot) = 0;
|
||||
};
|
||||
|
||||
#endif //!__ICONTRABAND__H__
|
||||
@@ -58,7 +58,10 @@ public:
|
||||
DUPLICATE = 3, // an object id exists in more than one place (day 0, so each item is flagged once)
|
||||
// different items share an object id and the login migration will not separate them: the characters holding
|
||||
// them already migrated, or a copy is in mail (day 0)
|
||||
ID_COLLISION = 4
|
||||
ID_COLLISION = 4,
|
||||
// a character has an item on the contraband list (value: how many, baseline: 1 when it was removed). Found when
|
||||
// the character loaded (day 0, one flag per item) or when the item was added (that day, item id 0)
|
||||
CONTRABAND = 5
|
||||
};
|
||||
|
||||
enum class eFlagStatus : uint8_t { OPEN = 0, DISMISSED = 1, ACTIONED = 2 };
|
||||
|
||||
@@ -215,6 +215,11 @@ public:
|
||||
std::vector<ZoneLimit> GetZoneLimits() override;
|
||||
void SetZoneLimit(const ZoneLimit& limit) override;
|
||||
void DeleteZoneLimit(uint32_t zoneId) override;
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override;
|
||||
void SetContrabandItem(const ContrabandItem& item) override;
|
||||
bool DeleteContrabandItem(LOT lot) override;
|
||||
|
||||
// IFeaturedProperties
|
||||
std::vector<FeaturedSlot> GetFeaturedPropertySlots() override;
|
||||
void SetFeaturedPropertySlot(const FeaturedSlot& slot) override;
|
||||
|
||||
@@ -18,6 +18,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
||||
"ServerOperations.cpp"
|
||||
"LiveOps.cpp"
|
||||
"FeaturedProperties.cpp"
|
||||
"Contraband.cpp"
|
||||
"MessageCaptures.cpp"
|
||||
"ChatLog.cpp"
|
||||
"RelatedData.cpp"
|
||||
|
||||
22
dDatabase/GameDatabase/MySQL/Tables/Contraband.cpp
Normal file
22
dDatabase/GameDatabase/MySQL/Tables/Contraband.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
std::vector<IContraband::ContrabandItem> MySQLDatabase::GetContrabandItems() {
|
||||
std::vector<ContrabandItem> items;
|
||||
auto result = ExecuteSelect("SELECT * FROM contraband_items ORDER BY lot;");
|
||||
while (result->next()) {
|
||||
items.push_back({ result->getInt("lot"), result->getString("reason").c_str(), static_cast<eContrabandAction>(result->getUInt("action")),
|
||||
result->getString("added_by").c_str(), result->getInt64("added_at") });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void MySQLDatabase::SetContrabandItem(const ContrabandItem& item) {
|
||||
ExecuteInsert(
|
||||
"INSERT INTO contraband_items (lot, reason, action, added_by, added_at) VALUES (?, ?, ?, ?, ?) "
|
||||
"ON DUPLICATE KEY UPDATE reason = VALUES(reason), action = VALUES(action), added_by = VALUES(added_by), added_at = VALUES(added_at);",
|
||||
item.lot, item.reason, static_cast<uint32_t>(item.action), item.addedBy, item.addedAt);
|
||||
}
|
||||
|
||||
bool MySQLDatabase::DeleteContrabandItem(LOT lot) {
|
||||
return ExecuteUpdate("DELETE FROM contraband_items WHERE lot = ?;", lot) > 0;
|
||||
}
|
||||
@@ -199,6 +199,11 @@ public:
|
||||
std::vector<ZoneLimit> GetZoneLimits() override;
|
||||
void SetZoneLimit(const ZoneLimit& limit) override;
|
||||
void DeleteZoneLimit(uint32_t zoneId) override;
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override;
|
||||
void SetContrabandItem(const ContrabandItem& item) override;
|
||||
bool DeleteContrabandItem(LOT lot) override;
|
||||
|
||||
// IFeaturedProperties
|
||||
std::vector<FeaturedSlot> GetFeaturedPropertySlots() override;
|
||||
void SetFeaturedPropertySlot(const FeaturedSlot& slot) override;
|
||||
|
||||
@@ -18,6 +18,7 @@ set(DDATABASES_DATABASES_SQLITE_TABLES_SOURCES
|
||||
"ServerOperations.cpp"
|
||||
"LiveOps.cpp"
|
||||
"FeaturedProperties.cpp"
|
||||
"Contraband.cpp"
|
||||
"MessageCaptures.cpp"
|
||||
"ChatLog.cpp"
|
||||
"RelatedData.cpp"
|
||||
|
||||
22
dDatabase/GameDatabase/SQLite/Tables/Contraband.cpp
Normal file
22
dDatabase/GameDatabase/SQLite/Tables/Contraband.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "SQLiteDatabase.h"
|
||||
|
||||
std::vector<IContraband::ContrabandItem> SQLiteDatabase::GetContrabandItems() {
|
||||
std::vector<ContrabandItem> items;
|
||||
auto [_, result] = ExecuteSelect("SELECT * FROM contraband_items ORDER BY lot;");
|
||||
for (; !result.eof(); result.nextRow()) {
|
||||
items.push_back({ result.getIntField("lot"), result.getStringField("reason"), static_cast<eContrabandAction>(result.getIntField("action")),
|
||||
result.getStringField("added_by"), result.getInt64Field("added_at") });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void SQLiteDatabase::SetContrabandItem(const ContrabandItem& item) {
|
||||
ExecuteInsert(
|
||||
"INSERT INTO contraband_items (lot, reason, action, added_by, added_at) VALUES (?, ?, ?, ?, ?) "
|
||||
"ON CONFLICT(lot) DO UPDATE SET reason = excluded.reason, action = excluded.action, added_by = excluded.added_by, added_at = excluded.added_at;",
|
||||
item.lot, item.reason, static_cast<uint32_t>(item.action), item.addedBy, item.addedAt);
|
||||
}
|
||||
|
||||
bool SQLiteDatabase::DeleteContrabandItem(LOT lot) {
|
||||
return ExecuteUpdate("DELETE FROM contraband_items WHERE lot = ?;", lot) > 0;
|
||||
}
|
||||
@@ -245,6 +245,11 @@ class TestSQLDatabase : public GameDatabase {
|
||||
std::vector<ZoneLimit> GetZoneLimits() override { return {}; }
|
||||
void SetZoneLimit(const ZoneLimit& limit) override {}
|
||||
void DeleteZoneLimit(uint32_t zoneId) override {}
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override { return {}; }
|
||||
void SetContrabandItem(const ContrabandItem& item) override {}
|
||||
bool DeleteContrabandItem(LOT lot) override { return false; }
|
||||
|
||||
// IFeaturedProperties
|
||||
std::vector<FeaturedSlot> GetFeaturedPropertySlots() override { return {}; }
|
||||
void SetFeaturedPropertySlot(const FeaturedSlot& slot) override {}
|
||||
|
||||
Reference in New Issue
Block a user