mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Implemented 'Inventory Snapshot' feature
This commit is contained in:
parent
41d19c4e8a
commit
a1089fccd6
@ -1,5 +1,16 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 09/25/2015 ==
|
||||
Uleat: Implemented 'Inventory Snapshot' feature to track online player inventories at timed intervals.
|
||||
rules:
|
||||
'Character:ActiveInvSnapshots' - active (true) or inactive (false - default)
|
||||
'Character:InvSnapshotMinIntervalM' - minimum time between snapshots (in minutes)
|
||||
'Character:InvSnapshotMinRetryM' - minimum time to attempt a retry after a failed snapshot (in minutes)
|
||||
'Character:InvSnapshotHistoryD' - minimum time to keep snapshot entries (in days)
|
||||
commands:
|
||||
'#invsnapshot' - Takes a snapshot of target client's inventory (feature active or inactive)
|
||||
'#clearinvsnapshots [use rule]' - Clears snapshot entries based on bool argument ([true] - honors the 'InvSnapshotHistoryD' rule, [false] - erases all)
|
||||
|
||||
== 08/02/2015 ==
|
||||
Shendare: VS2013 query StringFormat glitches when "%f" is passed for the int GetRunSpeed().
|
||||
Shendare: In CreateNewNPCCommand(), the npc_type_id and spawngroupid are created in the database, but never set in the spawn class, so later it can't delete them with #npcspawn remove or #npcspawn delete.
|
||||
|
||||
@ -2173,3 +2173,12 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database::ClearInvSnapshots(bool use_rule)
|
||||
{
|
||||
uint32 del_time = time(nullptr);
|
||||
if (use_rule) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; }
|
||||
|
||||
std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
@ -248,6 +248,8 @@ public:
|
||||
void SetLFP(uint32 CharID, bool LFP);
|
||||
void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon);
|
||||
|
||||
void ClearInvSnapshots(bool use_rule = true);
|
||||
|
||||
/* EQEmuLogSys */
|
||||
void LoadLogSettings(EQEmuLogSys::LogSettings* log_settings);
|
||||
|
||||
|
||||
@ -54,6 +54,8 @@ struct ExtendedProfile_Struct {
|
||||
uint32 mercTimerRemaining; /* Not Used */
|
||||
uint8 mercGender; /* Not Used */
|
||||
int32 mercState; /* Not Used */
|
||||
uint32 last_invsnapshot_time; /* Used */
|
||||
uint32 next_invsnapshot_time; /* Used */
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
@ -119,6 +119,10 @@ RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of
|
||||
RULE_INT(Character, IksarCommonTongue, 95) // 95 By default (live-like?)
|
||||
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)
|
||||
RULE_INT(Character, TrollCommonTongue, 95) // 95 By default (live-like?)
|
||||
RULE_BOOL(Character, ActiveInvSnapshots, false) // Takes a periodic snapshot of inventory contents from online players
|
||||
RULE_INT(Character, InvSnapshotMinIntervalM, 180) // Minimum time (in minutes) between inventory snapshots
|
||||
RULE_INT(Character, InvSnapshotMinRetryM, 30) // Time (in minutes) to re-attempt an inventory snapshot after a failure
|
||||
RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9086
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9087
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
#ifndef WIN32
|
||||
|
||||
@ -340,6 +340,7 @@
|
||||
9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty|
|
||||
9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty|
|
||||
9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty|
|
||||
9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
46
utils/sql/git/required/2015_09_25_inventory_snapshots.sql
Normal file
46
utils/sql/git/required/2015_09_25_inventory_snapshots.sql
Normal file
@ -0,0 +1,46 @@
|
||||
CREATE TABLE `inventory_snapshots` (
|
||||
`time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`charid` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`itemid` INT(11) UNSIGNED NULL DEFAULT '0',
|
||||
`charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
`color` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0',
|
||||
`augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0',
|
||||
`instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`custom_data` TEXT NULL,
|
||||
`ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornament_hero_model` INT(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`time_index`, `charid`, `slotid`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
ALTER TABLE `character_data` ADD COLUMN `e_last_invsnapshot` INT(11) UNSIGNED NOT NULL DEFAULT '0';
|
||||
|
||||
INSERT INTO `rule_values` VALUES
|
||||
(1, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'),
|
||||
(2, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'),
|
||||
(4, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'),
|
||||
(5, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'),
|
||||
(10, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'),
|
||||
(1, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'),
|
||||
(2, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'),
|
||||
(4, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'),
|
||||
(5, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'),
|
||||
(10, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'),
|
||||
(1, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'),
|
||||
(2, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'),
|
||||
(4, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'),
|
||||
(5, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'),
|
||||
(10, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'),
|
||||
(1, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'),
|
||||
(2, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'),
|
||||
(4, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'),
|
||||
(5, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'),
|
||||
(10, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries');
|
||||
@ -310,6 +310,8 @@ int main(int argc, char** argv) {
|
||||
database.ClearRaid();
|
||||
database.ClearRaidDetails();
|
||||
database.ClearRaidLeader();
|
||||
Log.Out(Logs::General, Logs::World_Server, "Clearing inventory snapshots..");
|
||||
database.ClearInvSnapshots();
|
||||
Log.Out(Logs::General, Logs::World_Server, "Loading items..");
|
||||
if(!database.LoadItems(hotfix_name))
|
||||
Log.Out(Logs::General, Logs::World_Server, "Error: Could not load item data. But ignoring");
|
||||
|
||||
@ -642,6 +642,17 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
|
||||
m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level, 0, 50000);
|
||||
m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level, 0, 50000);
|
||||
|
||||
// perform snapshot before SaveCharacterData() so that m_epp will contain the updated time
|
||||
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
||||
if (database.SaveCharacterInventorySnapshot(CharacterID())) {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
}
|
||||
else {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
}
|
||||
}
|
||||
|
||||
database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp, &m_epp); /* Save Character Data */
|
||||
|
||||
return true;
|
||||
|
||||
@ -1250,6 +1250,13 @@ public:
|
||||
|
||||
bool InterrogateInventory(Client* requester, bool log, bool silent, bool allowtrip, bool& error, bool autolog = true);
|
||||
|
||||
void SetNextInvSnapshot(uint32 interval_in_min) {
|
||||
m_epp.last_invsnapshot_time = time(nullptr);
|
||||
m_epp.next_invsnapshot_time = m_epp.last_invsnapshot_time + (interval_in_min * 60);
|
||||
}
|
||||
uint32 GetLastInvSnapshotTime() { return m_epp.last_invsnapshot_time; }
|
||||
uint32 GetNextInvSnapshotTime() { return m_epp.next_invsnapshot_time; }
|
||||
|
||||
//Command #Tune functions
|
||||
virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
|
||||
int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false);
|
||||
|
||||
@ -183,6 +183,7 @@ int command_init(void) {
|
||||
command_add("castspell", "[spellid] - Cast a spell", 50, command_castspell) ||
|
||||
command_add("chat", "[channel num] [message] - Send a channel message to all zones", 200, command_chat) ||
|
||||
command_add("checklos", "- Check for line of sight to your target", 50, command_checklos) ||
|
||||
command_add("clearinvsnapshots", "[use rule] - Clear inventory snapshot history (true - elapsed entries, false - all entries)", 200, command_clearinvsnapshots) ||
|
||||
command_add("close_shop", nullptr, 100, command_merchantcloseshop) ||
|
||||
command_add("connectworld", nullptr,0, command_connectworldserver) ||
|
||||
command_add("connectworldserver", "- Make zone attempt to connect to worldserver", 200, command_connectworldserver) ||
|
||||
@ -260,6 +261,7 @@ int command_init(void) {
|
||||
command_add("instance", "- Modify Instances", 200, command_instance) ||
|
||||
command_add("interrogateinv", "- use [help] argument for available options", 0, command_interrogateinv) ||
|
||||
command_add("interrupt", "[message id] [color] - Interrupt your casting. Arguments are optional.", 50, command_interrupt) ||
|
||||
command_add("invsnapshot", "- Takes an inventory snapshot of your current target", 80, command_invsnapshot) ||
|
||||
command_add("invul", nullptr,0, command_invul) ||
|
||||
command_add("invulnerable", "[on/off] - Turn player target's or your invulnerable flag on or off", 80, command_invul) ||
|
||||
command_add("ipban", "[IP address] - Ban IP by character name", 200, command_ipban) ||
|
||||
@ -2836,6 +2838,36 @@ void command_interrogateinv(Client *c, const Seperator *sep)
|
||||
c->Message(13, "An unknown error occurred while processing Client::InterrogateInventory()");
|
||||
}
|
||||
|
||||
void command_invsnapshot(Client *c, const Seperator *sep)
|
||||
{
|
||||
auto t = c->GetTarget();
|
||||
if (!t || !t->IsClient()) {
|
||||
c->Message(0, "Target must be a client");
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.SaveCharacterInventorySnapshot(((Client*)t)->CharacterID())) {
|
||||
c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
c->Message(0, "Successful inventory snapshot taken of %s", t->GetName());
|
||||
}
|
||||
else {
|
||||
c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
c->Message(0, "Failed to take inventory snapshot of %s", t->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
void command_clearinvsnapshots(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (strcmp(sep->arg[1], "false") == 0) {
|
||||
database.ClearInvSnapshots(false);
|
||||
c->Message(0, "Inventory snapshots cleared using current time");
|
||||
}
|
||||
else {
|
||||
database.ClearInvSnapshots();
|
||||
c->Message(0, "Inventory snapshots cleared using RuleI(Character, InvSnapshotHistoryD) (%i days)", RuleI(Character, InvSnapshotHistoryD));
|
||||
}
|
||||
}
|
||||
|
||||
void command_findnpctype(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(sep->arg[1][0] == 0) {
|
||||
|
||||
@ -154,6 +154,8 @@ void command_appearance(Client *c, const Seperator *sep);
|
||||
void command_nukeitem(Client *c, const Seperator *sep);
|
||||
void command_peekinv(Client *c, const Seperator *sep);
|
||||
void command_interrogateinv(Client *c, const Seperator *sep);
|
||||
void command_invsnapshot(Client *c, const Seperator *sep);
|
||||
void command_clearinvsnapshots(Client *c, const Seperator *sep);
|
||||
void command_findnpctype(Client *c, const Seperator *sep);
|
||||
void command_findzone(Client *c, const Seperator *sep);
|
||||
void command_viewnpctype(Client *c, const Seperator *sep);
|
||||
|
||||
@ -887,7 +887,8 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct*
|
||||
"RestTimer, "
|
||||
"`e_aa_effects`, "
|
||||
"`e_percent_to_aa`, "
|
||||
"`e_expended_aa_spent` "
|
||||
"`e_expended_aa_spent`, "
|
||||
"`e_last_invsnapshot` "
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `id` = %i ", character_id);
|
||||
@ -983,7 +984,9 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct*
|
||||
pp->RestTimer = atoi(row[r]); r++; // "RestTimer, "
|
||||
m_epp->aa_effects = atoi(row[r]); r++; // "`e_aa_effects`, "
|
||||
m_epp->perAA = atoi(row[r]); r++; // "`e_percent_to_aa`, "
|
||||
m_epp->expended_aa = atoi(row[r]); r++; // "`e_expended_aa_spent` "
|
||||
m_epp->expended_aa = atoi(row[r]); r++; // "`e_expended_aa_spent`, "
|
||||
m_epp->last_invsnapshot_time = atoi(row[r]); r++; // "`e_last_invsnapshot` "
|
||||
m_epp->next_invsnapshot_time = m_epp->last_invsnapshot_time + (RuleI(Character, InvSnapshotMinIntervalM) * 60);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1377,6 +1380,56 @@ bool ZoneDatabase::SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterInventorySnapshot(uint32 character_id){
|
||||
uint32 time_index = time(nullptr);
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO inventory_snapshots ("
|
||||
" time_index,"
|
||||
" charid,"
|
||||
" slotid,"
|
||||
" itemid,"
|
||||
" charges,"
|
||||
" color,"
|
||||
" augslot1,"
|
||||
" augslot2,"
|
||||
" augslot3,"
|
||||
" augslot4,"
|
||||
" augslot5,"
|
||||
" augslot6,"
|
||||
" instnodrop,"
|
||||
" custom_data,"
|
||||
" ornamenticon,"
|
||||
" ornamentidfile,"
|
||||
" ornament_hero_model"
|
||||
")"
|
||||
" SELECT"
|
||||
" %u,"
|
||||
" charid,"
|
||||
" slotid,"
|
||||
" itemid,"
|
||||
" charges,"
|
||||
" color,"
|
||||
" augslot1,"
|
||||
" augslot2,"
|
||||
" augslot3,"
|
||||
" augslot4,"
|
||||
" augslot5,"
|
||||
" augslot6,"
|
||||
" instnodrop,"
|
||||
" custom_data,"
|
||||
" ornamenticon,"
|
||||
" ornamentidfile,"
|
||||
" ornament_hero_model"
|
||||
" FROM inventory"
|
||||
" WHERE charid = %u",
|
||||
time_index,
|
||||
character_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterInventorySnapshot %i (%s)", character_id, (results.Success() ? "pass" : "fail"));
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp){
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
std::string query = StringFormat(
|
||||
@ -1473,7 +1526,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
" RestTimer, "
|
||||
" e_aa_effects, "
|
||||
" e_percent_to_aa, "
|
||||
" e_expended_aa_spent "
|
||||
" e_expended_aa_spent, "
|
||||
" e_last_invsnapshot "
|
||||
") "
|
||||
"VALUES ("
|
||||
"%u," // id " id, "
|
||||
@ -1568,7 +1622,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
"%u," // RestTimer pp->RestTimer, " RestTimer) "
|
||||
"%u," // e_aa_effects
|
||||
"%u," // e_percent_to_aa
|
||||
"%u" // e_expended_aa_spent
|
||||
"%u," // e_expended_aa_spent
|
||||
"%u" // e_last_invsnapshot
|
||||
")",
|
||||
character_id, // " id, "
|
||||
account_id, // " account_id, "
|
||||
@ -1662,7 +1717,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
pp->RestTimer, // " RestTimer) "
|
||||
m_epp->aa_effects,
|
||||
m_epp->perAA,
|
||||
m_epp->expended_aa
|
||||
m_epp->expended_aa,
|
||||
m_epp->last_invsnapshot_time
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
|
||||
|
||||
@ -290,6 +290,7 @@ public:
|
||||
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
|
||||
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
|
||||
bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterInventorySnapshot(uint32 character_id);
|
||||
|
||||
/* Character Data Deletes */
|
||||
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user