diff --git a/changelog.txt b/changelog.txt index f515e8e49..12a9fc76a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,13 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/18/2018 == +Uleat: Bug reporting fix and overhaul. + - Fixed bug reporting for SoD+ clients + - Added ability to disable bug reporting (set rule 'Bugs:ReportingSystemActive' to 'false') + - Implemented a more detailed reporting system (set rule 'Bugs:UseOldReportingMethod' to 'false') + -- New system is not currently compatible with script-based monitoring + - Soft-removal of defunct 'Petition Bug' system + == 02/14/2018 == mackal: Fix Heading -- Quests broken diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index a8fa73d1c..e5e9ae841 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -18,3 +18,68 @@ */ #include "emu_constants.h" + + +const char* EQEmu::bug::CategoryIDToCategoryName(CategoryID category_id) { + switch (category_id) { + case catVideo: + return "Video"; + case catAudio: + return "Audio"; + case catPathing: + return "Pathing"; + case catQuest: + return "Quest"; + case catTradeskills: + return "Tradeskills"; + case catSpellStacking: + return "Spell stacking"; + case catDoorsPortals: + return "Doors/Portals"; + case catItems: + return "Items"; + case catNPC: + return "NPC"; + case catDialogs: + return "Dialogs"; + case catLoNTCG: + return "LoN - TCG"; + case catMercenaries: + return "Mercenaries"; + case catOther: + default: + return "Other"; + } +} + +EQEmu::bug::CategoryID EQEmu::bug::CategoryNameToCategoryID(const char* category_name) { + if (!category_name) + return catOther; + + if (!strcmp(category_name, "Video")) + return catVideo; + if (!strcmp(category_name, "Audio")) + return catAudio; + if (!strcmp(category_name, "Pathing")) + return catPathing; + if (!strcmp(category_name, "Quest")) + return catQuest; + if (!strcmp(category_name, "Tradeskills")) + return catTradeskills; + if (!strcmp(category_name, "Spell stacking")) + return catSpellStacking; + if (!strcmp(category_name, "Doors/Portals")) + return catDoorsPortals; + if (!strcmp(category_name, "Items")) + return catItems; + if (!strcmp(category_name, "NPC")) + return catNPC; + if (!strcmp(category_name, "Dialogs")) + return catDialogs; + if (!strcmp(category_name, "LoN - TCG")) + return catLoNTCG; + if (!strcmp(category_name, "Mercenaries")) + return catMercenaries; + + return catOther; +} diff --git a/common/emu_constants.h b/common/emu_constants.h index e156fe98a..04e36849b 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -126,6 +126,37 @@ namespace EQEmu } /*constants*/ + namespace bug { + enum CategoryID : uint32 { + catOther = 0, + catVideo, + catAudio, + catPathing, + catQuest, + catTradeskills, + catSpellStacking, + catDoorsPortals, + catItems, + catNPC, + catDialogs, + catLoNTCG, + catMercenaries + }; + + enum OptionalInfoFlag : uint32 { + infoNoOptionalInfo = 0x0, + infoCanDuplicate = 0x1, + infoCrashBug = 0x2, + infoTargetInfo = 0x4, + infoCharacterFlags = 0x8, + infoUnknownValue = 0xFFFFFFF0 + }; + + const char* CategoryIDToCategoryName(CategoryID category_id); + CategoryID CategoryNameToCategoryID(const char* category_name); + + } // namespace bug + enum class CastingSlot : uint32 { Gem1 = 0, Gem2 = 1, diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 8452813f5..8b8949255 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3323,23 +3323,32 @@ struct GuildMakeLeader{ char target[64]; }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ char unknown308[160]; -/*0468*/ char target_name[64]; -/*0532*/ uint32 type; -/*0536*/ char unknown536[2052]; -/*2584*/ char bug[2048]; -/*4632*/ char unknown4632[6]; -/*4638*/ char system_info[4094]; +struct BugReport_Struct { +/*0000*/ uint32 category_id; +/*0004*/ char category_name[64]; +/*0068*/ char reporter_name[64]; +/*0132*/ char unused_0132[32]; +/*0164*/ char ui_path[128]; +/*0292*/ float pos_x; +/*0296*/ float pos_y; +/*0300*/ float pos_z; +/*0304*/ uint32 heading; +/*0308*/ uint32 unused_0308; +/*0312*/ uint32 time_played; +/*0316*/ char padding_0316[8]; +/*0324*/ uint32 target_id; +/*0328*/ char padding_0328[140]; +/*0468*/ uint32 unknown_0468; // seems to always be '0' +/*0472*/ char target_name[64]; +/*0536*/ uint32 optional_info_mask; + +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0540*/ char unused_0540[2052]; +/*2592*/ char bug_report[2050]; +/*4642*/ char system_info[4098]; +/*8740*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3366,20 +3375,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 5d42d9046..ecc288a35 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -3605,21 +3605,6 @@ struct GuildSetRank_Struct /*80*/ }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3646,20 +3631,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 8de4fb9ab..bd9cbbce9 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -3545,21 +3545,6 @@ struct GuildSetRank_Struct /*80*/ }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3586,20 +3571,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index a77feedbc..ceba224f4 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -2933,25 +2933,6 @@ namespace SoD FINISH_DIRECT_DECODE(); } - DECODE(OP_Bug) - { - DECODE_LENGTH_EXACT(structs::BugStruct); - SETUP_DIRECT_DECODE(BugStruct, structs::BugStruct); - - strn0cpy(emu->chartype, eq->chartype, sizeof(emu->chartype)); - strn0cpy(emu->name, eq->name, sizeof(emu->name)); - strn0cpy(emu->ui, eq->ui, sizeof(emu->ui)); - IN(x); - IN(y); - IN(z); - IN(heading); - strn0cpy(emu->target_name, eq->target_name, sizeof(emu->target_name)); - strn0cpy(emu->bug, eq->bug, sizeof(emu->bug)); - strn0cpy(emu->system_info, eq->system_info, sizeof(emu->system_info)); - - FINISH_DIRECT_DECODE(); - } - DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); diff --git a/common/patches/sod_ops.h b/common/patches/sod_ops.h index 90c28b2eb..7c1109499 100644 --- a/common/patches/sod_ops.h +++ b/common/patches/sod_ops.h @@ -104,7 +104,6 @@ D(OP_AugmentInfo) D(OP_AugmentItem) D(OP_BazaarSearch) D(OP_Buff) -D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 88a78c6ee..76635108d 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -3008,24 +3008,6 @@ struct GuildMakeLeader{ char target[64]; }; -struct BugStruct{ -/*0000*/ uint32 type1; //seems to be just a different way of seeing type; seems to be ordered completely differently -/*0004*/ char chartype[64]; -/*0068*/ char name[96]; -/*0164*/ char ui[128]; -/*0292*/ float x; -/*0296*/ float y; -/*0300*/ float z; -/*0304*/ float heading; -/*0308*/ uint32 unknown304; -/*0312*/ char unknown308[160]; -/*0472*/ char target_name[64]; -/*0536*/ uint32 type; -/*0540*/ char unknown536[2052]; -/*2588*/ char bug[2048]; -/*4636*/ char unknown4632[6]; -/*4642*/ char system_info[4094]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3052,20 +3034,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 9df6ca1df..bee75b6c2 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -2385,6 +2385,17 @@ namespace SoF FINISH_DIRECT_DECODE(); } + DECODE(OP_Bug) + { + DECODE_LENGTH_EXACT(structs::BugReport_Struct); + SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct); + + emu->category_id = EQEmu::bug::CategoryNameToCategoryID(eq->category_name); + memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct)); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); diff --git a/common/patches/sof_ops.h b/common/patches/sof_ops.h index 180857388..c4e42d8d4 100644 --- a/common/patches/sof_ops.h +++ b/common/patches/sof_ops.h @@ -95,6 +95,7 @@ D(OP_ApplyPoison) D(OP_AugmentInfo) D(OP_AugmentItem) D(OP_Buff) +D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 9d87bd83a..ca1c93ed2 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -2906,23 +2906,31 @@ struct GuildMakeLeader{ char target[64]; }; +struct BugReport_Struct { +/*0000*/ char category_name[64]; +/*0064*/ char character_name[64]; +/*0128*/ char unused_0128[32]; +/*0160*/ char ui_path[128]; +/*0288*/ float pos_x; +/*0292*/ float pos_y; +/*0296*/ float pos_z; +/*0300*/ uint32 heading; +/*0304*/ uint32 unused_0304; +/*0308*/ uint32 time_played; +/*0312*/ char padding_0312[8]; +/*0320*/ uint32 target_id; +/*0324*/ char padding_0324[140]; +/*0464*/ uint32 unknown_0464; // seems to always be '0' +/*0468*/ char target_name[64]; +/*0532*/ uint32 optional_info_mask; - -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0536*/ char unused_0536[2052]; +/*2588*/ char bug_report[2050]; +/*4638*/ char system_info[4098]; +/*8736*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -2949,20 +2957,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 45f267223..2c010713d 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1789,6 +1789,17 @@ namespace Titanium FINISH_DIRECT_DECODE(); } + DECODE(OP_Bug) + { + DECODE_LENGTH_EXACT(structs::BugReport_Struct); + SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct); + + emu->category_id = EQEmu::bug::CategoryNameToCategoryID(eq->category_name); + memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct)); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index 9f77a7077..dafb8b903 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -78,6 +78,7 @@ D(OP_AdventureMerchantSell) D(OP_ApplyPoison) D(OP_AugmentItem) D(OP_Buff) +D(OP_Bug) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index e52b7628c..41f029c8d 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -2571,21 +2571,32 @@ struct GuildMakeLeader{ char name[64]; char target[64]; }; -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; + +struct BugReport_Struct { +/*0000*/ char category_name[64]; +/*0064*/ char character_name[64]; +/*0128*/ char unused_0128[32]; +/*0160*/ char ui_path[128]; +/*0288*/ float pos_x; +/*0292*/ float pos_y; +/*0296*/ float pos_z; +/*0300*/ uint32 heading; +/*0304*/ uint32 unused_0304; +/*0308*/ uint32 time_played; +/*0312*/ char padding_0312[8]; +/*0320*/ uint32 target_id; +/*0324*/ char padding_0324[140]; +/*0464*/ uint32 unknown_0464; // seems to always be '0' +/*0468*/ char target_name[64]; +/*0532*/ uint32 optional_info_mask; + +// this looks like a butchered 8k buffer with 2 trailing dword fields +/*0536*/ char unused_0536[2052]; +/*2588*/ char bug_report[2050]; +/*4638*/ char system_info[4098]; +/*8736*/ }; + struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -2612,20 +2623,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index cc5564e11..b10e3a3dd 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -3060,23 +3060,6 @@ struct GuildMakeLeader{ char target[64]; }; - - -struct BugStruct{ -/*0000*/ char chartype[64]; -/*0064*/ char name[96]; -/*0160*/ char ui[128]; -/*0288*/ float x; -/*0292*/ float y; -/*0296*/ float z; -/*0300*/ float heading; -/*0304*/ uint32 unknown304; -/*0308*/ uint32 type; -/*0312*/ char unknown312[2144]; -/*2456*/ char bug[1024]; -/*3480*/ char placeholder[2]; -/*3482*/ char system_info[4098]; -}; struct Make_Pet_Struct { //Simple struct for getting pet info uint8 level; uint8 class_; @@ -3103,20 +3086,21 @@ struct Ground_Spawn{ struct Ground_Spawns { struct Ground_Spawn spawn[50]; //Assigned max number to allow }; -struct PetitionBug_Struct{ - uint32 petition_number; - uint32 unknown4; - char accountname[64]; - uint32 zoneid; - char name[64]; - uint32 level; - uint32 class_; - uint32 race; - uint32 unknown152[3]; - uint32 time; - uint32 unknown168; - char text[1028]; -}; + +//struct PetitionBug_Struct{ +// uint32 petition_number; +// uint32 unknown4; +// char accountname[64]; +// uint32 zoneid; +// char name[64]; +// uint32 level; +// uint32 class_; +// uint32 race; +// uint32 unknown152[3]; +// uint32 time; +// uint32 unknown168; +// char text[1028]; +//}; struct ApproveZone_Struct { char name[64]; diff --git a/common/ruletypes.h b/common/ruletypes.h index 24d9e809b..219995913 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -720,6 +720,12 @@ RULE_BOOL(Client, UseLiveFactionMessage, false) // Allows players to see faction RULE_BOOL(Client, UseLiveBlockedMessage, false) // Allows players to see faction adjustments like Live RULE_CATEGORY_END() +RULE_CATEGORY(Bugs) +RULE_BOOL(Bugs, ReportingSystemActive, true) // Activates bug reporting +RULE_BOOL(Bugs, UseOldReportingMethod, true) // Forces the use of the old bug reporting system +RULE_BOOL(Bugs, DumpTargetEntity, false) // Dumps the target entity, if one is provided +RULE_CATEGORY_END() + #undef RULE_CATEGORY #undef RULE_INT #undef RULE_REAL diff --git a/common/version.h b/common/version.h index 412223b8c..d1afd9744 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9120 +#define CURRENT_BINARY_DATABASE_VERSION 9121 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9018 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 4de5f3d8f..2a0b12fd2 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -374,6 +374,7 @@ 9118|2018_02_04_Charm_Stats.sql|SHOW COLUMNS FROM `npc_types` LIKE 'charm_ac'|empty| 9119|2018_02_10_GlobalLoot.sql|SHOW TABLES LIKE 'global_loot'|empty| 9120|2018_02_13_Heading.sql|SELECT value FROM variables WHERE varname = 'fixed_heading'|empty| +9121|2018_02_18_bug_reports.sql|SHOW TABLES LIKE 'bug_reports'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_02_18_bug_reports.sql b/utils/sql/git/required/2018_02_18_bug_reports.sql new file mode 100644 index 000000000..92afbd7c9 --- /dev/null +++ b/utils/sql/git/required/2018_02_18_bug_reports.sql @@ -0,0 +1,44 @@ +CREATE TABLE `bug_reports` ( + `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `zone` VARCHAR(32) NOT NULL DEFAULT 'Unknown', + `client_version_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `client_version_name` VARCHAR(24) NOT NULL DEFAULT 'Unknown', + `account_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `character_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `character_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `reporter_spoof` TINYINT(1) NOT NULL DEFAULT '1', + `category_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `category_name` VARCHAR(64) NOT NULL DEFAULT 'Other', + `reporter_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `ui_path` VARCHAR(128) NOT NULL DEFAULT 'Unknown', + `pos_x` FLOAT NOT NULL DEFAULT '0', + `pos_y` FLOAT NOT NULL DEFAULT '0', + `pos_z` FLOAT NOT NULL DEFAULT '0', + `heading` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `time_played` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `target_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `target_name` VARCHAR(64) NOT NULL DEFAULT 'Unknown', + `optional_info_mask` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `_can_duplicate` TINYINT(1) NOT NULL DEFAULT '0', + `_crash_bug` TINYINT(1) NOT NULL DEFAULT '0', + `_target_info` TINYINT(1) NOT NULL DEFAULT '0', + `_character_flags` TINYINT(1) NOT NULL DEFAULT '0', + `_unknown_value` TINYINT(1) NOT NULL DEFAULT '0', + `bug_report` VARCHAR(1024) NOT NULL DEFAULT '', + `system_info` VARCHAR(1024) NOT NULL DEFAULT '', + `report_datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `bug_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `last_review` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `last_reviewer` VARCHAR(64) NOT NULL DEFAULT 'None', + `reviewer_notes` VARCHAR(1024) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE INDEX `id` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES +(1, 'Bugs:ReportingSystemActive', 'true', 'Activates bug reporting'), +(1, 'Bugs:UseOldReportingMethod', 'true', 'Forces the use of the old bug reporting system'), +(1, 'Bugs:DumpTargetEntity', 'false', 'Dumps the target entity, if one is provided'); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 2de71acc8..07085ee71 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3960,12 +3960,23 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app) void Client::Handle_OP_Bug(const EQApplicationPacket *app) { - if (app->size != sizeof(BugStruct)) - printf("Wrong size of BugStruct got %d expected %zu!\n", app->size, sizeof(BugStruct)); - else { - BugStruct* bug = (BugStruct*)app->pBuffer; - database.UpdateBug(bug); + if (!RuleB(Bugs, ReportingSystemActive)) { + Message(0, "Bug reporting is disabled on this server."); + return; } + + if (app->size != sizeof(BugReport_Struct)) { + printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct)); + } + else { + BugReport_Struct* bug_report = (BugReport_Struct*)app->pBuffer; + + if (RuleB(Bugs, UseOldReportingMethod)) + database.RegisterBug(bug_report); + else + database.RegisterBug(this, bug_report); + } + return; } @@ -10553,11 +10564,8 @@ void Client::Handle_OP_Petition(const EQApplicationPacket *app) void Client::Handle_OP_PetitionBug(const EQApplicationPacket *app) { - if (app->size != sizeof(PetitionBug_Struct)) - printf("Wrong size of BugStruct! Expected: %zu, Got: %i\n", sizeof(PetitionBug_Struct), app->size); - else { - Message(0, "Petition Bugs are not supported, please use /bug."); - } + Message(0, "Petition Bugs are not supported, please use /bug."); + return; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 01add9944..d5db09a53 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -325,62 +325,260 @@ bool ZoneDatabase::logevents(const char* accountname,uint32 accountid,uint8 stat return true; } +void ZoneDatabase::RegisterBug(BugReport_Struct* bug_report) { + if (!bug_report) + return; -void ZoneDatabase::UpdateBug(BugStruct* bug) { - - uint32 len = strlen(bug->bug); - char* bugtext = nullptr; - if(len > 0) - { - bugtext = new char[2*len+1]; - memset(bugtext, 0, 2*len+1); - DoEscapeString(bugtext, bug->bug, len); + size_t len = 0; + char* name_ = nullptr; + char* ui_ = nullptr; + char* type_ = nullptr; + char* target_ = nullptr; + char* bug_ = nullptr; + + len = strlen(bug_report->reporter_name); + if (len) { + if (len > 63) // check against db column size + len = 63; + name_ = new char[(2 * len + 1)]; + memset(name_, 0, (2 * len + 1)); + DoEscapeString(name_, bug_report->reporter_name, len); } - len = strlen(bug->ui); - char* uitext = nullptr; - if(len > 0) - { - uitext = new char[2*len+1]; - memset(uitext, 0, 2*len+1); - DoEscapeString(uitext, bug->ui, len); + len = strlen(bug_report->ui_path); + if (len) { + if (len > 127) + len = 127; + ui_ = new char[(2 * len + 1)]; + memset(ui_, 0, (2 * len + 1)); + DoEscapeString(ui_, bug_report->ui_path, len); } - len = strlen(bug->target_name); - char* targettext = nullptr; - if(len > 0) - { - targettext = new char[2*len+1]; - memset(targettext, 0, 2*len+1); - DoEscapeString(targettext, bug->target_name, len); + len = strlen(bug_report->category_name); + if (len) { + if (len > 63) + len = 63; + type_ = new char[(2 * len + 1)]; + memset(type_, 0, (2 * len + 1)); + DoEscapeString(type_, bug_report->category_name, len); } - //x and y are intentionally swapped because eq is inversexy coords - std::string query = StringFormat("INSERT INTO bugs (zone, name, ui, x, y, z, type, flag, target, bug, date) " + len = strlen(bug_report->target_name); + if (len) { + if (len > 63) + len = 63; + target_ = new char[(2 * len + 1)]; + memset(target_, 0, (2 * len + 1)); + DoEscapeString(target_, bug_report->target_name, len); + } + + len = strlen(bug_report->bug_report); + if (len) { + if (len > 1023) + len = 1023; + bug_ = new char[(2 * len + 1)]; + memset(bug_, 0, (2 * len + 1)); + DoEscapeString(bug_, bug_report->bug_report, len); + } + + //x and y are intentionally swapped because eq is inversexy coords //is this msg out-of-date or are the parameters wrong? + std::string query = StringFormat( + "INSERT INTO `bugs` (`zone`, `name`, `ui`, `x`, `y`, `z`, `type`, `flag`, `target`, `bug`, `date`) " "VALUES('%s', '%s', '%s', '%.2f', '%.2f', '%.2f', '%s', %d, '%s', '%s', CURDATE())", - zone->GetShortName(), bug->name, uitext == nullptr ? "": uitext, - bug->x, bug->y, bug->z, bug->chartype, bug->type, targettext == nullptr? "Unknown Target": targettext, - bugtext==nullptr?"":bugtext); - safe_delete_array(bugtext); - safe_delete_array(uitext); - safe_delete_array(targettext); + zone->GetShortName(), + (name_ ? name_ : ""), + (ui_ ? ui_ : ""), + bug_report->pos_x, + bug_report->pos_y, + bug_report->pos_z, + (type_ ? type_ : ""), + bug_report->optional_info_mask, + (target_ ? target_ : "Unknown Target"), + (bug_ ? bug_ : "") + ); + safe_delete_array(name_); + safe_delete_array(ui_); + safe_delete_array(type_); + safe_delete_array(target_); + safe_delete_array(bug_); + QueryDatabase(query); } -void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug){ +void ZoneDatabase::RegisterBug(Client* client, BugReport_Struct* bug_report) { + if (!client || !bug_report) + return; - uint32 len = strlen(bug->text); - auto bugtext = new char[2 * len + 1]; - memset(bugtext, 0, 2*len+1); - DoEscapeString(bugtext, bug->text, len); + size_t len = 0; + char* category_name_ = nullptr; + char* reporter_name_ = nullptr; + char* ui_path_ = nullptr; + char* target_name_ = nullptr; + char* bug_report_ = nullptr; + char* system_info_ = nullptr; - std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) " - "VALUES('%s', '%s', '%s', %i)", - "Petition", bug->name, bugtext, 25); - safe_delete_array(bugtext); - QueryDatabase(query); + len = strlen(bug_report->category_name); + if (len) { + if (len > 63) // check against db column size + len = 63; + category_name_ = new char[(2 * len + 1)]; + memset(category_name_, 0, (2 * len + 1)); + DoEscapeString(category_name_, bug_report->category_name, len); + } + + len = strlen(bug_report->reporter_name); + if (len) { + if (len > 63) + len = 63; + reporter_name_ = new char[(2 * len + 1)]; + memset(reporter_name_, 0, (2 * len + 1)); + DoEscapeString(reporter_name_, bug_report->reporter_name, len); + } + + len = strlen(bug_report->ui_path); + if (len) { + if (len > 127) + len = 127; + ui_path_ = new char[(2 * len + 1)]; + memset(ui_path_, 0, (2 * len + 1)); + DoEscapeString(ui_path_, bug_report->ui_path, len); + } + + len = strlen(bug_report->target_name); + if (len) { + if (len > 63) + len = 63; + target_name_ = new char[(2 * len + 1)]; + memset(target_name_, 0, (2 * len + 1)); + DoEscapeString(target_name_, bug_report->target_name, len); + } + + len = strlen(bug_report->bug_report); + if (len) { + if (len > 1023) + len = 1023; + bug_report_ = new char[(2 * len + 1)]; + memset(bug_report_, 0, (2 * len + 1)); + DoEscapeString(bug_report_, bug_report->bug_report, len); + } + + len = strlen(bug_report->system_info); + if (len) { + if (len > 1023) + len = 1023; + system_info_ = new char[(2 * len + 1)]; + memset(system_info_, 0, (2 * len + 1)); + DoEscapeString(system_info_, bug_report->system_info, len); + } + + std::string query = StringFormat( + "INSERT INTO `bug_reports` " + "(`zone`," + " `client_version_id`," + " `client_version_name`," + " `account_id`," + " `character_id`," + " `character_name`," + " `reporter_spoof`," + " `category_id`," + " `category_name`," + " `reporter_name`," + " `ui_path`," + " `pos_x`," + " `pos_y`," + " `pos_z`," + " `heading`," + " `time_played`," + " `target_id`," + " `target_name`," + " `optional_info_mask`," + " `_can_duplicate`," + " `_crash_bug`," + " `_target_info`," + " `_character_flags`," + " `_unknown_value`," + " `bug_report`," + " `system_info`) " + "VALUES " + "('%s'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%s'," + " '%s'," + " '%s'," + " '%1.1f'," + " '%1.1f'," + " '%1.1f'," + " '%u'," + " '%u'," + " '%u'," + " '%s'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%s'," + " '%s')", + zone->GetShortName(), + client->ClientVersion(), + EQEmu::versions::ClientVersionName(client->ClientVersion()), + client->AccountID(), + client->CharacterID(), + client->GetName(), + (strcmp(client->GetName(), reporter_name_) != 0 ? 1 : 0), + bug_report->category_id, + (category_name_ ? category_name_ : ""), + (reporter_name_ ? reporter_name_ : ""), + (ui_path_ ? ui_path_ : ""), + bug_report->pos_x, + bug_report->pos_y, + bug_report->pos_z, + bug_report->heading, + bug_report->time_played, + bug_report->target_id, + (target_name_ ? target_name_ : ""), + bug_report->optional_info_mask, + ((bug_report->optional_info_mask & EQEmu::bug::infoCanDuplicate) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoCrashBug) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoTargetInfo) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoCharacterFlags) != 0 ? 1 : 0), + ((bug_report->optional_info_mask & EQEmu::bug::infoUnknownValue) != 0 ? 1 : 0), + (bug_report_ ? bug_report_ : ""), + (system_info_ ? system_info_ : "") + ); + safe_delete_array(category_name_); + safe_delete_array(reporter_name_); + safe_delete_array(ui_path_); + safe_delete_array(target_name_); + safe_delete_array(bug_report_); + safe_delete_array(system_info_); + + auto result = QueryDatabase(query); + + // TODO: Entity dumping [RuleB(Bugs, DumpTargetEntity)] } +//void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug) { +// +// uint32 len = strlen(bug->text); +// auto bugtext = new char[2 * len + 1]; +// memset(bugtext, 0, 2 * len + 1); +// DoEscapeString(bugtext, bug->text, len); +// +// std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) " +// "VALUES('%s', '%s', '%s', %i)", +// "Petition", bug->name, bugtext, 25); +// safe_delete_array(bugtext); +// QueryDatabase(query); +//} + bool ZoneDatabase::SetSpecialAttkFlag(uint8 id, const char* flag) { std::string query = StringFormat("UPDATE npc_types SET npcspecialattks='%s' WHERE id = %i;", flag, id); diff --git a/zone/zonedb.h b/zone/zonedb.h index 6f65bae91..d0e7b1a99 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -442,8 +442,9 @@ public: bool DeleteMerc(uint32 merc_id); /* Petitions */ - void UpdateBug(BugStruct* bug); - void UpdateBug(PetitionBug_Struct* bug); + void RegisterBug(BugReport_Struct* bug_report); // old method + void RegisterBug(Client* client, BugReport_Struct* bug_report); // new method + //void UpdateBug(PetitionBug_Struct* bug); void DeletePetitionFromDB(Petition* wpet); void UpdatePetitionToDB(Petition* wpet); void InsertPetitionToDB(Petition* wpet);