diff --git a/apps/installer/includes/os_configs/windows.sh b/apps/installer/includes/os_configs/windows.sh index 6f49052a3..6957ba62d 100644 --- a/apps/installer/includes/os_configs/windows.sh +++ b/apps/installer/includes/os_configs/windows.sh @@ -26,4 +26,4 @@ choco install -y --skip-checksums "${INSTALL_ARGS[@]}" cmake.install -y --insta choco install -y --skip-checksums "${INSTALL_ARGS[@]}" visualstudio2022-workload-nativedesktop choco install -y --skip-checksums "${INSTALL_ARGS[@]}" openssl --force --version=3.6.2 choco install -y --skip-checksums "${INSTALL_ARGS[@]}" boost-msvc-14.3 --force --version=1.87.0 -choco install -y --skip-checksums "${INSTALL_ARGS[@]}" mysql --force --version=8.4.6 +choco install -y --skip-checksums "${INSTALL_ARGS[@]}" mysql --force --version=8.4.9 diff --git a/data/sql/updates/db_auth/2026_05_01_00.sql b/data/sql/updates/db_auth/2026_05_01_00.sql new file mode 100644 index 000000000..0f271638d --- /dev/null +++ b/data/sql/updates/db_auth/2026_05_01_00.sql @@ -0,0 +1,1007 @@ +-- DB update 2025_07_24_00 -> 2026_05_01_00 +-- RBAC System for AzerothCore +-- Ported from TrinityCore + +-- Permission List table +DROP TABLE IF EXISTS `rbac_account_permissions`; +DROP TABLE IF EXISTS `rbac_default_permissions`; +DROP TABLE IF EXISTS `rbac_linked_permissions`; +DROP TABLE IF EXISTS `rbac_permissions`; + +CREATE TABLE `rbac_permissions` ( + `id` int unsigned NOT NULL DEFAULT '0' COMMENT 'Permission id', + `name` varchar(100) NOT NULL COMMENT 'Permission name', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Permission List'; + +-- Permission to Permission relation (for role inheritance) +CREATE TABLE `rbac_linked_permissions` ( + `id` int unsigned NOT NULL COMMENT 'Permission id', + `linkedId` int unsigned NOT NULL COMMENT 'Linked Permission id', + PRIMARY KEY (`id`,`linkedId`), + KEY `fk__rbac_linked_permissions__rbac_permissions1` (`id`), + KEY `fk__rbac_linked_permissions__rbac_permissions2` (`linkedId`), + CONSTRAINT `fk__rbac_linked_permissions__rbac_permissions1` FOREIGN KEY (`id`) REFERENCES `rbac_permissions` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk__rbac_linked_permissions__rbac_permissions2` FOREIGN KEY (`linkedId`) REFERENCES `rbac_permissions` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Permission - Linked Permission relation'; + +-- Default permissions by security level +CREATE TABLE `rbac_default_permissions` ( + `secId` int unsigned NOT NULL COMMENT 'Security Level id', + `permissionId` int unsigned NOT NULL COMMENT 'permission id', + `realmId` int NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`secId`,`permissionId`,`realmId`), + KEY `fk__rbac_default_permissions__rbac_permissions` (`permissionId`), + CONSTRAINT `fk__rbac_default_permissions__rbac_permissions` FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Default permission to assign to different account security levels'; + +-- Account specific permissions +CREATE TABLE `rbac_account_permissions` ( + `accountId` int unsigned NOT NULL COMMENT 'Account id', + `permissionId` int unsigned NOT NULL COMMENT 'Permission id', + `granted` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Granted = 1, Denied = 0', + `realmId` int NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`accountId`,`permissionId`,`realmId`), + KEY `fk__rbac_account_roles__rbac_permissions` (`permissionId`), + CONSTRAINT `fk__rbac_account_permissions__account` FOREIGN KEY (`accountId`) REFERENCES `account` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk__rbac_account_roles__rbac_permissions` FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Account-Permission relation'; + +-- ============================================================================ +-- Insert permissions +-- ============================================================================ +INSERT INTO `rbac_permissions` VALUES +-- Core permissions (1-53) +(1,'Instant logout'), +(2,'Skip Queue'), +(3,'Join Normal Battleground'), +(4,'Join Random Battleground'), +(5,'Join Arenas'), +(6,'Join Dungeon Finder'), +(7,'Skip idle connection check'), +(8,'Cannot earn achievements'), +(9,'Cannot earn realm first achievements'), +(11,'Log GM trades'), +(13,'Skip Instance required bosses check'), +(14,'Skip character creation team mask check'), +(15,'Skip character creation class mask check'), +(16,'Skip character creation race mask check'), +(17,'Skip character creation reserved name check'), +(18,'Skip character creation death knight min level check'), +(19,'Skip needed requirements to use channel check'), +(20,'Skip disable map check'), +(21,'Skip reset talents when used more than allowed check'), +(22,'Skip spam chat check'), +(23,'Skip over-speed ping check'), +(24,'Two side faction characters on the same account'), +(25,'Allow say chat between factions'), +(26,'Allow channel chat between factions'), +(27,'Two side mail interaction'), +(28,'See two side who list'), +(29,'Add friends of other faction'), +(30,'Save character without delay with .save command'), +(31,'Use params with .unstuck command'), +(32,'Can be assigned tickets with .assign ticket command'), +(33,'Notify if a command was not found'), +(34,'Check if should appear in list using .gm ingame command'), +(35,'See all security levels with who command'), +(36,'Filter whispers'), +(37,'Use staff badge in chat'), +(38,'Resurrect with full Health Points'), +(39,'Restore saved gm setting states'), +(40,'Allows to add a gm to friend list'), +(41,'Use Config option START_GM_LEVEL to assign new character level'), +(42,'Allows to use CMSG_WORLD_TELEPORT opcode'), +(43,'Allows to use CMSG_WHOIS opcode'), +(44,'Receive global GM messages/texts'), +(45,'Join channels without announce'), +(46,'Change channel settings without being channel moderator'), +(47,'Can ignore lower security checks'), +(48,'Enable IP, Last Login and EMail output in pinfo'), +(49,'Forces to enter the email for confirmation on password change'), +(50,'Allow user to check his own email with .account'), +(51,'Allow trading between factions'), +(52,'No battleground deserter debuff'), +(53,'Can be AFK on the battleground'), +-- Roles (192-199) +(192,'Role: Sec Level Administrator'), +(193,'Role: Sec Level Gamemaster'), +(194,'Role: Sec Level Moderator'), +(195,'Role: Sec Level Player'), +(196,'Role: Administrator Commands'), +(197,'Role: Gamemaster Commands'), +(198,'Role: Moderator Commands'), +(199,'Role: Player Commands'), +-- RBAC commands (200-206) +(200,'Command: rbac'), +(201,'Command: rbac account'), +(202,'Command: rbac account list'), +(203,'Command: rbac account grant'), +(204,'Command: rbac account deny'), +(205,'Command: rbac account revoke'), +(206,'Command: rbac list'), +-- Account commands (217-229) +(217,'Command: account'), +(218,'Command: account addon'), +(219,'Command: account create'), +(220,'Command: account delete'), +(221,'Command: account lock'), +(222,'Command: account lock country'), +(223,'Command: account lock ip'), +(224,'Command: account onlinelist'), +(225,'Command: account password'), +(226,'Command: account set'), +(227,'Command: account set addon'), +(228,'Command: account set gmlevel'), +(229,'Command: account set password'), +-- Achievement commands (231-232) +(231,'Command: achievement add'), +(232,'Command: achievement checkall'), +-- Arena commands (233-238) +(233,'Command: arena captain'), +(234,'Command: arena create'), +(235,'Command: arena disband'), +(236,'Command: arena info'), +(237,'Command: arena lookup'), +(238,'Command: arena rename'), +-- Ban commands (240-256) +(240,'Command: ban account'), +(241,'Command: ban character'), +(242,'Command: ban ip'), +(243,'Command: ban playeraccount'), +(245,'Command: baninfo account'), +(246,'Command: baninfo character'), +(247,'Command: baninfo ip'), +(249,'Command: banlist account'), +(250,'Command: banlist character'), +(251,'Command: banlist ip'), +(253,'Command: unban account'), +(254,'Command: unban character'), +(255,'Command: unban ip'), +(256,'Command: unban playeraccount'), +-- Battlefield commands (258-262) +(258,'Command: bf start'), +(259,'Command: bf stop'), +(260,'Command: bf switch'), +(261,'Command: bf timer'), +(262,'Command: bf enable'), +-- Account email commands (263-266) +(263,'Command: account email'), +(265,'Command: account set sec email'), +(266,'Command: account set sec regmail'), +-- Cast commands (267-272) +(267,'Command: cast'), +(268,'Command: cast back'), +(269,'Command: cast dist'), +(270,'Command: cast self'), +(271,'Command: cast target'), +(272,'Command: cast dest'), +-- Character commands (274-290) +(274,'Command: character customize'), +(275,'Command: character changefaction'), +(276,'Command: character changerace'), +(278,'Command: character deleted delete'), +(279,'Command: character deleted list'), +(280,'Command: character deleted restore'), +(281,'Command: character deleted old'), +(282,'Command: character erase'), +(283,'Command: character level'), +(284,'Command: character rename'), +(285,'Command: character reputation'), +(286,'Command: character titles'), +(287,'Command: levelup'), +(289,'Command: pdump load'), +(290,'Command: pdump write'), +-- Cheat commands (292-299) +(292,'Command: cheat casttime'), +(293,'Command: cheat cooldown'), +(294,'Command: cheat explore'), +(295,'Command: cheat god'), +(296,'Command: cheat power'), +(297,'Command: cheat status'), +(298,'Command: cheat taxi'), +(299,'Command: cheat waterwalk'), +-- Debug command (300) +(300,'Command: debug'), +-- Deserter commands (343-347) +(343,'Command: deserter bg add'), +(344,'Command: deserter bg remove'), +(346,'Command: deserter instance add'), +(347,'Command: deserter instance remove'), +-- Disable commands (350-366) +(350,'Command: disable add achievement_criteria'), +(351,'Command: disable add battleground'), +(352,'Command: disable add map'), +(353,'Command: disable add mmap'), +(354,'Command: disable add outdoorpvp'), +(355,'Command: disable add quest'), +(356,'Command: disable add spell'), +(357,'Command: disable add vmap'), +(359,'Command: disable remove achievement_criteria'), +(360,'Command: disable remove battleground'), +(361,'Command: disable remove map'), +(362,'Command: disable remove mmap'), +(363,'Command: disable remove outdoorpvp'), +(364,'Command: disable remove quest'), +(365,'Command: disable remove spell'), +(366,'Command: disable remove vmap'), +-- Event commands (367-370) +(367,'Command: event info'), +(368,'Command: event activelist'), +(369,'Command: event start'), +(370,'Command: event stop'), +-- GM commands (371-376) +(371,'Command: gm'), +(372,'Command: gm chat'), +(373,'Command: gm fly'), +(374,'Command: gm ingame'), +(375,'Command: gm list'), +(376,'Command: gm visible'), +-- Go command (377) +(377,'Command: go'), +-- Gobject commands (388-399) +(388,'Command: gobject activate'), +(389,'Command: gobject add'), +(390,'Command: gobject add temp'), +(391,'Command: gobject delete'), +(392,'Command: gobject info'), +(393,'Command: gobject move'), +(394,'Command: gobject near'), +(396,'Command: gobject set phase'), +(397,'Command: gobject set state'), +(398,'Command: gobject target'), +(399,'Command: gobject turn'), +-- Guild commands (401-407) +(401,'Command: guild'), +(402,'Command: guild create'), +(403,'Command: guild delete'), +(404,'Command: guild invite'), +(405,'Command: guild uninvite'), +(406,'Command: guild rank'), +(407,'Command: guild rename'), +-- Honor commands (409-411) +(409,'Command: honor add'), +(410,'Command: honor add kill'), +(411,'Command: honor update'), +-- Instance commands (413-416) +(413,'Command: instance listbinds'), +(414,'Command: instance unbind'), +(415,'Command: instance stats'), +(416,'Command: instance savedata'), +-- Learn commands (417-429) +(417,'Command: learn'), +(419,'Command: learn all my'), +(420,'Command: learn all my class'), +(421,'Command: learn my pettalents'), +(422,'Command: learn all my spells'), +(423,'Command: learn all talents'), +(424,'Command: learn all gm'), +(425,'Command: learn all crafts'), +(426,'Command: learn all default'), +(427,'Command: learn all lang'), +(428,'Command: learn all recipes'), +(429,'Command: unlearn'), +-- LFG commands (431-436) +(431,'Command: lfg player'), +(432,'Command: lfg group'), +(433,'Command: lfg queue'), +(434,'Command: lfg clean'), +(435,'Command: lfg options'), +(436,'Command: lfg cooldown'), +-- List commands (437-441) +(437,'Command: list creature'), +(438,'Command: list item'), +(439,'Command: list object'), +(440,'Command: list auras'), +(441,'Command: list mail'), +-- Lookup commands (442-461) +(442,'Command: lookup'), +(443,'Command: lookup area'), +(444,'Command: lookup creature'), +(445,'Command: lookup event'), +(446,'Command: lookup faction'), +(447,'Command: lookup item'), +(448,'Command: lookup itemset'), +(449,'Command: lookup object'), +(450,'Command: lookup quest'), +(451,'Command: lookup player'), +(452,'Command: lookup player ip'), +(453,'Command: lookup player account'), +(454,'Command: lookup player email'), +(455,'Command: lookup skill'), +(456,'Command: lookup spell'), +(457,'Command: lookup spell id'), +(458,'Command: lookup taxinode'), +(459,'Command: lookup tele'), +(460,'Command: lookup title'), +(461,'Command: lookup map'), +-- Announce/Channel commands (462-471) +(462,'Command: announce'), +(463,'Command: channel'), +(464,'Command: channel set'), +(465,'Command: channel set ownership'), +(466,'Command: gmannounce'), +(467,'Command: gmnameannounce'), +(468,'Command: gmnotify'), +(469,'Command: nameannounce'), +(470,'Command: notify'), +(471,'Command: whispers'), +-- Group commands (472-478) +(472,'Command: group'), +(473,'Command: group leader'), +(474,'Command: group disband'), +(475,'Command: group remove'), +(476,'Command: group join'), +(477,'Command: group list'), +(478,'Command: group summon'), +-- Pet commands (479-482) +(479,'Command: pet'), +(480,'Command: pet create'), +(481,'Command: pet learn'), +(482,'Command: pet unlearn'), +-- Send commands (483-487) +(483,'Command: send'), +(484,'Command: send items'), +(485,'Command: send mail'), +(486,'Command: send message'), +(487,'Command: send money'), +-- Misc commands (488-535) +(488,'Command: additem'), +(489,'Command: additemset'), +(490,'Command: appear'), +(491,'Command: aura'), +(492,'Command: bank'), +(493,'Command: bindsight'), +(494,'Command: combatstop'), +(495,'Command: cometome'), +(496,'Command: commands'), +(497,'Command: cooldown'), +(498,'Command: damage'), +(499,'Command: dev'), +(500,'Command: die'), +(501,'Command: dismount'), +(502,'Command: distance'), +(503,'Command: flusharenapoints'), +(504,'Command: freeze'), +(505,'Command: gps'), +(506,'Command: guid'), +(507,'Command: help'), +(508,'Command: hidearea'), +(509,'Command: itemmove'), +(510,'Command: kick'), +(511,'Command: linkgrave'), +(512,'Command: listfreeze'), +(513,'Command: maxskill'), +(514,'Command: movegens'), +(515,'Command: mute'), +(516,'Command: neargrave'), +(517,'Command: pinfo'), +(518,'Command: playall'), +(519,'Command: possess'), +(520,'Command: recall'), +(521,'Command: repairitems'), +(522,'Command: respawn'), +(523,'Command: revive'), +(524,'Command: saveall'), +(525,'Command: save'), +(526,'Command: setskill'), +(527,'Command: showarea'), +(528,'Command: summon'), +(529,'Command: unaura'), +(530,'Command: unbindsight'), +(531,'Command: unfreeze'), +(532,'Command: unmute'), +(533,'Command: unpossess'), +(534,'Command: unstuck'), +(535,'Command: wchange'), +-- MMap commands (536-541) +(536,'Command: mmap'), +(537,'Command: mmap loadedtiles'), +(538,'Command: mmap loc'), +(539,'Command: mmap path'), +(540,'Command: mmap stats'), +(541,'Command: mmap testarea'), +-- Morph commands (542-543) +(542,'Command: morph'), +(543,'Command: demorph'), +-- Modify commands (544-569) +(544,'Command: modify'), +(545,'Command: modify arenapoints'), +(546,'Command: modify bit'), +(547,'Command: modify drunk'), +(548,'Command: modify energy'), +(549,'Command: modify faction'), +(550,'Command: modify gender'), +(551,'Command: modify honor'), +(552,'Command: modify hp'), +(553,'Command: modify mana'), +(554,'Command: modify money'), +(555,'Command: modify mount'), +(556,'Command: modify phase'), +(557,'Command: modify rage'), +(558,'Command: modify reputation'), +(559,'Command: modify runicpower'), +(560,'Command: modify scale'), +(561,'Command: modify speed'), +(562,'Command: modify speed all'), +(563,'Command: modify speed backwalk'), +(564,'Command: modify speed fly'), +(565,'Command: modify speed walk'), +(566,'Command: modify speed swim'), +(567,'Command: modify spell'), +(568,'Command: modify standstate'), +(569,'Command: modify talentpoints'), +-- NPC commands (571-601) +(571,'Command: npc add'), +(572,'Command: npc add formation'), +(573,'Command: npc add item'), +(574,'Command: npc add move'), +(575,'Command: npc add temp'), +(576,'Command: npc delete'), +(577,'Command: npc delete item'), +(578,'Command: npc follow'), +(579,'Command: npc follow stop'), +(580,'Command: npc set'), +(581,'Command: npc set allowmove'), +(582,'Command: npc set entry'), +(583,'Command: npc set factionid'), +(584,'Command: npc set flag'), +(585,'Command: npc set level'), +(586,'Command: npc set link'), +(587,'Command: npc set model'), +(588,'Command: npc set movetype'), +(589,'Command: npc set phase'), +(590,'Command: npc set spawndist'), +(591,'Command: npc set spawntime'), +(592,'Command: npc set data'), +(593,'Command: npc info'), +(594,'Command: npc near'), +(595,'Command: npc move'), +(596,'Command: npc playemote'), +(597,'Command: npc say'), +(598,'Command: npc textemote'), +(599,'Command: npc whisper'), +(600,'Command: npc yell'), +(601,'Command: npc tame'), +-- Quest commands (602-606) +(602,'Command: quest'), +(603,'Command: quest add'), +(604,'Command: quest complete'), +(605,'Command: quest remove'), +(606,'Command: quest reward'), +-- Reload commands (607-709) +(607,'Command: reload'), +(608,'Command: reload access_requirement'), +(609,'Command: reload achievement_criteria_data'), +(610,'Command: reload achievement_reward'), +(611,'Command: reload all'), +(612,'Command: reload all achievement'), +(613,'Command: reload all area'), +(614,'Command: reload broadcast_text'), +(615,'Command: reload all gossips'), +(616,'Command: reload all item'), +(617,'Command: reload all locales'), +(618,'Command: reload all loot'), +(619,'Command: reload all npc'), +(620,'Command: reload all quest'), +(621,'Command: reload all scripts'), +(622,'Command: reload all spell'), +(623,'Command: reload areatrigger_involvedrelation'), +(624,'Command: reload areatrigger_tavern'), +(625,'Command: reload areatrigger_teleport'), +(626,'Command: reload auctions'), +(627,'Command: reload autobroadcast'), +(629,'Command: reload conditions'), +(630,'Command: reload config'), +(631,'Command: reload battleground_template'), +(632,'Command: mutehistory'), +(633,'Command: reload creature_linked_respawn'), +(634,'Command: reload creature_loot_template'), +(635,'Command: reload creature_onkill_reputation'), +(636,'Command: reload creature_questender'), +(637,'Command: reload creature_queststarter'), +(638,'Command: reload creature_summon_groups'), +(639,'Command: reload creature_template'), +(640,'Command: reload creature_text'), +(641,'Command: reload disables'), +(642,'Command: reload disenchant_loot_template'), +(643,'Command: reload event_scripts'), +(644,'Command: reload fishing_loot_template'), +(645,'Command: reload graveyard_zone'), +(646,'Command: reload game_tele'), +(647,'Command: reload gameobject_questender'), +(648,'Command: reload gameobject_quest_loot_template'), +(649,'Command: reload gameobject_queststarter'), +(650,'Command: reload gm_tickets'), +(651,'Command: reload gossip_menu'), +(652,'Command: reload gossip_menu_option'), +(653,'Command: reload item_enchantment_template'), +(654,'Command: reload item_loot_template'), +(655,'Command: reload item_set_names'), +(656,'Command: reload lfg_dungeon_rewards'), +(657,'Command: reload achievement_reward_locale'), +(658,'Command: reload creature_template_locale'), +(659,'Command: reload creature_text_locale'), +(660,'Command: reload gameobject_template_locale'), +(661,'Command: reload gossip_menu_option_locale'), +(662,'Command: reload item_template_locale'), +(663,'Command: reload item_set_name_locale'), +(664,'Command: reload npc_text_locale'), +(665,'Command: reload page_text_locale'), +(666,'Command: reload points_of_interest_locale'), +(667,'Command: reload quest_template_locale'), +(668,'Command: reload mail_level_reward'), +(669,'Command: reload mail_loot_template'), +(670,'Command: reload milling_loot_template'), +(671,'Command: reload npc_spellclick_spells'), +(672,'Command: reload trainer'), +(673,'Command: reload npc_vendor'), +(674,'Command: reload page_text'), +(675,'Command: reload pickpocketing_loot_template'), +(676,'Command: reload points_of_interest'), +(677,'Command: reload prospecting_loot_template'), +(678,'Command: reload quest_poi'), +(679,'Command: reload quest_template'), +(680,'Command: reload rbac'), +(681,'Command: reload reference_loot_template'), +(682,'Command: reload reserved_name'), +(683,'Command: reload reputation_reward_rate'), +(684,'Command: reload reputation_spillover_template'), +(685,'Command: reload skill_discovery_template'), +(686,'Command: reload skill_extra_item_template'), +(687,'Command: reload skill_fishing_base_level'), +(688,'Command: reload skinning_loot_template'), +(689,'Command: reload smart_scripts'), +(690,'Command: reload spell_required'), +(691,'Command: reload spell_area'), +(692,'Command: reload spell_bonus_data'), +(693,'Command: reload spell_group'), +(694,'Command: reload spell_learn_spell'), +(695,'Command: reload spell_loot_template'), +(696,'Command: reload spell_linked_spell'), +(697,'Command: reload spell_pet_auras'), +(698,'Command: character changeaccount'), +(699,'Command: reload spell_proc'), +(701,'Command: reload spell_target_position'), +(702,'Command: reload spell_threats'), +(703,'Command: reload spell_group_stack_rules'), +(704,'Command: reload acore_string'), +(706,'Command: reload waypoint_scripts'), +(707,'Command: reload waypoint_data'), +(708,'Command: reload vehicle_accessory'), +(709,'Command: reload vehicle_template_accessory'), +-- Reset commands (710-717) +(710,'Command: reset'), +(711,'Command: reset achievements'), +(712,'Command: reset honor'), +(713,'Command: reset level'), +(714,'Command: reset spells'), +(715,'Command: reset stats'), +(716,'Command: reset talents'), +(717,'Command: reset all'), +-- Server commands (718-736) +(718,'Command: server'), +(719,'Command: server corpses'), +(720,'Command: server exit'), +(721,'Command: server idlerestart'), +(722,'Command: server idlerestart cancel'), +(723,'Command: server idleshutdown'), +(724,'Command: server idleshutdown cancel'), +(725,'Command: server info'), +(726,'Command: server plimit'), +(727,'Command: server restart'), +(728,'Command: server restart cancel'), +(729,'Command: server set'), +(730,'Command: server set closed'), +(731,'Command: server set difftime'), +(732,'Command: server set loglevel'), +(733,'Command: server set motd'), +(734,'Command: server shutdown'), +(735,'Command: server shutdown cancel'), +(736,'Command: server motd'), +-- Tele commands (737-741) +(737,'Command: tele'), +(738,'Command: tele add'), +(739,'Command: tele del'), +(740,'Command: tele name'), +(741,'Command: tele group'), +-- Ticket commands (742-760) +(742,'Command: ticket'), +(743,'Command: ticket assign'), +(744,'Command: ticket close'), +(745,'Command: ticket closedlist'), +(746,'Command: ticket comment'), +(747,'Command: ticket complete'), +(748,'Command: ticket delete'), +(749,'Command: ticket escalate'), +(750,'Command: ticket escalatedlist'), +(751,'Command: ticket list'), +(752,'Command: ticket onlinelist'), +(753,'Command: ticket reset'), +(754,'Command: ticket response'), +(755,'Command: ticket response append'), +(756,'Command: ticket response appendln'), +(757,'Command: ticket togglesystem'), +(758,'Command: ticket unassign'), +(759,'Command: ticket viewid'), +(760,'Command: ticket viewname'), +-- Titles commands (762-766) +(762,'Command: titles add'), +(763,'Command: titles current'), +(764,'Command: titles remove'), +(766,'Command: titles set mask'), +-- WP commands (767-774) +(767,'Command: wp'), +(768,'Command: wp add'), +(769,'Command: wp event'), +(770,'Command: wp load'), +(771,'Command: wp modify'), +(772,'Command: wp unload'), +(773,'Command: wp reload'), +(774,'Command: wp show'), +-- Mailbox command (777) +(777,'Command: mailbox'), +-- AHBot commands (779-793) +(779,'Command: ahbot items'), +(780,'Command: ahbot items gray'), +(781,'Command: ahbot items white'), +(782,'Command: ahbot items green'), +(783,'Command: ahbot items blue'), +(784,'Command: ahbot items purple'), +(785,'Command: ahbot items orange'), +(786,'Command: ahbot items yellow'), +(787,'Command: ahbot ratio'), +(788,'Command: ahbot ratio alliance'), +(789,'Command: ahbot ratio horde'), +(790,'Command: ahbot ratio neutral'), +(791,'Command: ahbot rebuild'), +(792,'Command: ahbot reload'), +(793,'Command: ahbot status'), +-- Guild info / Instance boss / PVPStats / Modify XP (794-798) +(794,'Command: guild info'), +(795,'Command: instance setbossstate'), +(796,'Command: instance getbossstate'), +(797,'Command: pvpstats'), +(798,'Command: modify xp'), +-- Additional commands (837-843) +(837,'Command: npc evade'), +(838,'Command: pet level'), +(839,'Command: server shutdown force'), +(840,'Command: server restart force'), +(841,'Command: neargraveyard'), +(843,'Command: reload quest_greeting'), +-- Spawngroup / Group / NPC / List commands (856-868) +(856,'Command: npc spawngroup'), +(857,'Command: npc despawngroup'), +(858,'Command: gobject spawngroup'), +(859,'Command: gobject despawngroup'), +(860,'Command: list respawns'), +(861,'Command: group set'), +(862,'Command: group set assistant'), +(863,'Command: group set maintank'), +(864,'Command: group set mainassist'), +(865,'Command: npc showloot'), +(866,'Command: list spawnpoints'), +(867,'Command: reload quest_greeting_locale'), +(868,'Command: group revive'), +-- Server debug / Reload / Settings / Lookup (872-877) +(872,'Command: server debug'), +(873,'Command: reload creature_movement_override'), +(874,'Command: settings announcer'), +(875,'Command: lookup map id'), +(876,'Command: lookup item id'), +(877,'Command: lookup quest id'), +-- PDump copy / Reload vehicle template (880-881) +(880,'Command: pdump copy'), +(881,'Command: reload vehicle_template'), +-- BG start/stop (884-885) +(884,'Command: bg start'), +(885,'Command: bg stop'), +-- AC-specific commands (886-896) +(886,'Command: item restore'), +(887,'Command: item restore list'), +(888,'Command: item refund'), +(889,'Command: commentator'), +(890,'Command: skirmish'), +(891,'Command: string'), +(892,'Command: opendoor'), +(893,'Command: beastmaster'), +(894,'Command: packetlog'), +(895,'Command: aura stack'), +(896,'Command: respawn all'), +-- Gear / Spectator commands (897-904) +(897,'Command: gear repair'), +(898,'Command: gear stats'), +(899,'Command: spect'), +(900,'Command: spect version'), +(901,'Command: spect reset'), +(902,'Command: spect spectate'), +(903,'Command: spect watch'), +(904,'Command: spect leave'), +-- Arena season commands (905-908) +(905,'Command: arena season state'), +(906,'Command: arena season reward'), +(907,'Command: arena season deleteteams'), +(908,'Command: arena season start'), +-- Character check commands (909-911) +(909,'Command: character check bank'), +(910,'Command: character check bag'), +(911,'Command: character check profession'), +(912,'Command: gobject load'), +(913,'Command: bf queue'); + +-- ============================================================================ +-- Link roles to permissions +-- ============================================================================ +INSERT INTO `rbac_linked_permissions` VALUES +-- --------------------------------------------------------------------------- +-- Role 192 (Administrator): Core admin permissions + links to GM role and Admin commands +-- --------------------------------------------------------------------------- +(192, 7), -- Skip idle check +(192, 21), -- Skip talent reset check +(192, 42), -- World teleport opcode +(192, 43), -- Whois opcode +(192, 193), -- Links to GM role +(192, 196), -- Admin commands role +-- --------------------------------------------------------------------------- +-- Role 193 (Gamemaster): GM-specific core permissions + links to Mod role and GM commands +-- --------------------------------------------------------------------------- +(193, 45), -- Join channels without announce +(193, 48), -- Pinfo personal data +(193, 52), -- No BG deserter debuff +(193, 53), -- Can AFK in BG +(193, 194), -- Links to Moderator role +(193, 197), -- GM commands role +-- --------------------------------------------------------------------------- +-- Role 194 (Moderator): Moderator core permissions + links to Player role and Mod commands +-- --------------------------------------------------------------------------- +(194, 1), -- Instant logout +(194, 2), -- Skip queue +(194, 9), -- Cannot earn realm first achievements +(194, 11), -- Log GM trades +(194, 13), -- Skip instance required bosses check +(194, 14), -- Skip character creation team mask check +(194, 15), -- Skip character creation class mask check +(194, 16), -- Skip character creation race mask check +(194, 17), -- Skip character creation reserved name check +(194, 18), -- Skip character creation death knight check +(194, 19), -- Skip channel requirements check +(194, 20), -- Skip disable map check +(194, 22), -- Skip spam chat check +(194, 23), -- Skip over-speed ping check +(194, 25), -- Allow say chat between factions +(194, 26), -- Allow channel chat between factions +(194, 27), -- Two side mail interaction +(194, 28), -- See two side who list +(194, 29), -- Add friends of other faction +(194, 30), -- Save without delay +(194, 31), -- Unstuck with args +(194, 32), -- Can be assigned tickets +(194, 33), -- Notify command not found +(194, 34), -- Appear in GM list +(194, 35), -- See all sec levels +(194, 36), -- Filter whispers +(194, 37), -- Staff badge +(194, 38), -- Resurrect full HP +(194, 39), -- Restore GM state +(194, 40), -- Allow GM friend +(194, 41), -- Start GM level +(194, 44), -- Receive global GM messages +(194, 46), -- Change channel settings +(194, 47), -- Ignore lower security +(194, 51), -- Allow two side trade +(194, 195), -- Links to Player role +(194, 198), -- Mod commands role +(194, 632), -- Mutehistory +(194, 798), -- Modify XP +-- --------------------------------------------------------------------------- +-- Role 195 (Player): Basic player permissions + player commands +-- --------------------------------------------------------------------------- +(195, 3), -- Join BG +(195, 4), -- Join Random BG +(195, 5), -- Join Arenas +(195, 6), -- Join Dungeon Finder +(195, 24), -- Two side character creation +(195, 49), -- Email confirm for pass change +(195, 199), -- Player commands role +-- --------------------------------------------------------------------------- +-- Role 196 (Admin Commands): Server management, reload, reset, disable, etc. +-- --------------------------------------------------------------------------- +-- RBAC commands +(196, 200), (196, 201), (196, 202), (196, 203), (196, 204), (196, 205), (196, 206), +-- Account administration +(196, 219), (196, 220), (196, 224), (196, 226), (196, 227), (196, 228), (196, 229), +(196, 265), (196, 266), +-- Battlefield management +(196, 258), (196, 259), (196, 260), (196, 261), (196, 262), +-- Character admin (destructive operations) +(196, 278), (196, 281), (196, 282), (196, 698), +-- PDump +(196, 289), (196, 290), (196, 880), +-- Disable commands +(196, 350), (196, 351), (196, 352), (196, 353), (196, 354), (196, 355), (196, 356), (196, 357), +(196, 359), (196, 360), (196, 361), (196, 362), (196, 363), (196, 364), (196, 365), (196, 366), +-- Channel management +(196, 463), (196, 464), (196, 465), +-- Mass operations +(196, 503), (196, 511), (196, 524), +-- Reload commands +(196, 607), (196, 608), (196, 609), (196, 610), (196, 611), (196, 612), (196, 613), (196, 614), +(196, 615), (196, 616), (196, 617), (196, 618), (196, 619), (196, 620), (196, 621), (196, 622), +(196, 623), (196, 624), (196, 625), (196, 626), (196, 627), (196, 629), (196, 630), (196, 631), +(196, 633), (196, 634), (196, 635), (196, 636), (196, 637), (196, 638), (196, 639), (196, 640), +(196, 641), (196, 642), (196, 643), (196, 644), (196, 645), (196, 646), (196, 647), (196, 648), +(196, 649), (196, 650), (196, 651), (196, 652), (196, 653), (196, 654), (196, 655), (196, 656), +(196, 657), (196, 658), (196, 659), (196, 660), (196, 661), (196, 662), (196, 663), (196, 664), +(196, 665), (196, 666), (196, 667), (196, 668), (196, 669), (196, 670), (196, 671), (196, 672), +(196, 673), (196, 674), (196, 675), (196, 676), (196, 677), (196, 678), (196, 679), (196, 680), +(196, 681), (196, 682), (196, 683), (196, 684), (196, 685), (196, 686), (196, 687), (196, 688), +(196, 689), (196, 690), (196, 691), (196, 692), (196, 693), (196, 694), (196, 695), (196, 696), +(196, 697), (196, 699), (196, 701), (196, 702), (196, 703), (196, 704), (196, 706), (196, 707), +(196, 708), (196, 709), +(196, 843), (196, 867), (196, 873), (196, 881), +-- Reset commands +(196, 710), (196, 711), (196, 712), (196, 713), (196, 714), (196, 715), (196, 716), (196, 717), +-- Server commands +(196, 718), (196, 719), (196, 720), (196, 721), (196, 722), (196, 723), (196, 724), +(196, 726), (196, 727), (196, 728), (196, 729), (196, 730), (196, 731), (196, 732), +(196, 733), (196, 734), (196, 735), (196, 736), +(196, 839), (196, 840), (196, 872), +-- Ticket admin (destructive) +(196, 748), (196, 753), (196, 757), +-- WP reload +(196, 773), +-- Mailbox +(196, 777), +-- AHBot +(196, 779), (196, 780), (196, 781), (196, 782), (196, 783), (196, 784), (196, 785), +(196, 786), (196, 787), (196, 788), (196, 789), (196, 790), (196, 791), (196, 792), (196, 793), +-- Gobject load / List spawnpoints +(196, 912), (196, 866), +-- Arena season commands +(196, 905), (196, 906), (196, 907), (196, 908), +-- AC-specific admin commands +(196, 886), (196, 887), (196, 888), (196, 891), (196, 894), (196, 896), +-- --------------------------------------------------------------------------- +-- Role 197 (GM Commands): Game manipulation, character, NPC, gobject, quest, etc. +-- --------------------------------------------------------------------------- +-- Achievement +(197, 231), (197, 232), +-- Arena +(197, 233), (197, 234), (197, 235), (197, 236), (197, 237), (197, 238), +-- Cast +(197, 267), (197, 268), (197, 269), (197, 270), (197, 271), (197, 272), +-- Character +(197, 274), (197, 275), (197, 276), (197, 279), (197, 280), +(197, 283), (197, 284), (197, 285), (197, 286), (197, 287), +(197, 909), (197, 910), (197, 911), +-- Cheat +(197, 292), (197, 293), (197, 294), (197, 295), (197, 296), (197, 297), (197, 298), (197, 299), +-- Debug +(197, 300), +-- Deserter +(197, 343), (197, 344), (197, 346), (197, 347), +-- Event +(197, 367), (197, 368), (197, 369), (197, 370), +-- GM / Go +(197, 371), (197, 372), (197, 373), (197, 376), (197, 377), +-- Gobject +(197, 388), (197, 389), (197, 390), (197, 391), (197, 392), (197, 393), (197, 394), +(197, 396), (197, 397), (197, 398), (197, 399), +-- Guild +(197, 401), (197, 402), (197, 403), (197, 404), (197, 405), (197, 406), (197, 407), +-- Honor +(197, 409), (197, 410), (197, 411), +-- Instance +(197, 413), (197, 414), (197, 415), (197, 416), +-- Learn +(197, 417), (197, 419), (197, 420), (197, 421), (197, 422), (197, 423), (197, 424), +(197, 425), (197, 426), (197, 427), (197, 428), (197, 429), +-- LFG +(197, 431), (197, 432), (197, 433), (197, 434), (197, 435), (197, 436), +-- List +(197, 437), (197, 438), (197, 439), (197, 440), (197, 441), +-- Lookup (GM-level) +(197, 445), (197, 448), (197, 449), (197, 451), (197, 452), (197, 453), (197, 454), +(197, 457), (197, 458), (197, 460), (197, 461), +-- Group +(197, 472), (197, 473), (197, 474), (197, 475), (197, 476), (197, 477), (197, 478), +-- Pet +(197, 479), (197, 480), (197, 481), (197, 482), +-- Send +(197, 483), (197, 484), (197, 485), (197, 486), (197, 487), +-- Misc game commands +(197, 488), (197, 489), (197, 490), (197, 491), (197, 492), (197, 493), (197, 494), (197, 495), +(197, 497), (197, 498), (197, 499), (197, 500), +(197, 502), (197, 504), (197, 506), (197, 508), (197, 509), +(197, 512), (197, 513), (197, 514), (197, 516), (197, 518), (197, 519), (197, 520), +(197, 521), (197, 522), (197, 523), (197, 526), (197, 527), (197, 528), (197, 529), (197, 530), (197, 531), +(197, 533), (197, 535), +-- MMap +(197, 536), (197, 537), (197, 538), (197, 539), (197, 540), (197, 541), +-- Morph +(197, 542), (197, 543), +-- Modify +(197, 544), (197, 545), (197, 546), (197, 547), (197, 548), (197, 549), (197, 550), (197, 551), +(197, 552), (197, 553), (197, 554), (197, 555), (197, 556), (197, 557), (197, 558), (197, 559), +(197, 560), (197, 561), (197, 562), (197, 563), (197, 564), (197, 565), (197, 566), (197, 567), +(197, 568), (197, 569), +-- NPC +(197, 571), (197, 572), (197, 573), (197, 574), (197, 575), (197, 576), (197, 577), (197, 578), +(197, 579), (197, 580), (197, 581), (197, 582), (197, 583), (197, 584), (197, 585), (197, 586), +(197, 587), (197, 588), (197, 589), (197, 590), (197, 591), (197, 592), (197, 593), (197, 594), +(197, 595), (197, 596), (197, 597), (197, 598), (197, 599), (197, 600), (197, 601), +-- Quest +(197, 602), (197, 603), (197, 604), (197, 605), (197, 606), +-- Tele +(197, 737), (197, 738), (197, 739), (197, 740), (197, 741), +-- Titles +(197, 762), (197, 763), (197, 764), (197, 766), +-- WP (except reload which is in 196) +(197, 767), (197, 768), (197, 769), (197, 770), (197, 771), (197, 772), (197, 774), +-- Guild info / Instance boss state / Modify XP +(197, 794), (197, 795), (197, 796), (197, 798), +-- NPC evade / Pet level / Neargraveyard +(197, 837), (197, 838), (197, 841), +-- Spawngroup / List respawns +(197, 856), (197, 857), (197, 858), (197, 859), (197, 860), +-- Group set / NPC showloot +(197, 861), (197, 862), (197, 863), (197, 864), (197, 865), +-- Group revive / Settings announcer +(197, 868), (197, 874), +-- Lookup map/item/quest id +(197, 875), (197, 876), (197, 877), +-- BG start/stop / BF queue +(197, 884), (197, 885), (197, 913), +-- AC-specific GM commands +(197, 889), (197, 890), (197, 892), (197, 893), (197, 895), +-- Gear repair +(197, 897), +-- --------------------------------------------------------------------------- +-- Role 198 (Mod Commands): Community management - ban, mute, kick, tickets, announce +-- --------------------------------------------------------------------------- +-- Ban/Unban +(198, 240), (198, 241), (198, 242), (198, 243), +(198, 245), (198, 246), (198, 247), +(198, 249), (198, 250), (198, 251), +(198, 253), (198, 254), (198, 255), (198, 256), +-- Announce/Notify +(198, 462), (198, 466), (198, 467), (198, 468), (198, 469), (198, 470), (198, 471), +-- Kick/Mute/Pinfo/Unmute +(198, 510), (198, 515), (198, 517), (198, 532), +-- Mutehistory +(198, 632), +-- Ticket commands (excluding admin-only 748 delete, 753 reset, 757 togglesystem) +(198, 742), (198, 743), (198, 744), (198, 745), (198, 746), (198, 747), +(198, 749), (198, 750), (198, 751), (198, 752), +(198, 754), (198, 755), (198, 756), (198, 758), (198, 759), (198, 760), +-- --------------------------------------------------------------------------- +-- Role 199 (Player Commands): Self-service account management, basic lookups +-- --------------------------------------------------------------------------- +-- Account self-management +(199, 217), (199, 218), (199, 221), (199, 222), (199, 223), (199, 225), (199, 263), +-- GM info +(199, 374), (199, 375), +-- Lookup (basic) +(199, 442), (199, 443), (199, 444), (199, 446), (199, 447), (199, 450), (199, 455), (199, 456), (199, 459), +-- Basic commands +(199, 496), (199, 501), (199, 505), (199, 507), (199, 525), (199, 534), +-- Server info / PVPStats +(199, 725), (199, 797), +-- Gear stats +(199, 898), +-- Spectator +(199, 899), (199, 900), (199, 901), (199, 902), (199, 903), (199, 904); + +-- ============================================================================ +-- Default permissions by security level +-- ============================================================================ +-- SEC_PLAYER = 0 gets Player role (195) +-- SEC_MODERATOR = 1 gets Moderator role (194, which includes 195) +-- SEC_GAMEMASTER = 2 gets GM role (193, which includes 194) +-- SEC_ADMINISTRATOR = 3 gets Admin role (192, which includes 193) +INSERT INTO `rbac_default_permissions` VALUES +(3, 192, -1), -- Admin gets Admin role +(2, 193, -1), -- GM gets GM role +(1, 194, -1), -- Moderator gets Mod role +(0, 195, -1); -- Player gets Player role diff --git a/data/sql/updates/db_world/2026_04_25_00.sql b/data/sql/updates/db_world/2026_04_25_00.sql new file mode 100644 index 000000000..2a06f464d --- /dev/null +++ b/data/sql/updates/db_world/2026_04_25_00.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_24_02 -> 2026_04_25_00 +-- +DELETE FROM `spell_cooldown_overrides` WHERE `Id`=62306; diff --git a/data/sql/updates/db_world/2026_04_25_01.sql b/data/sql/updates/db_world/2026_04_25_01.sql new file mode 100644 index 000000000..b73fef093 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_25_01.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_25_00 -> 2026_04_25_01 +-- Ironhand Guardian (entry 8982) should never enter combat +UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 0x2000 WHERE `entry` = 8982; diff --git a/data/sql/updates/db_world/2026_04_25_02.sql b/data/sql/updates/db_world/2026_04_25_02.sql new file mode 100644 index 000000000..958c20d50 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_25_02.sql @@ -0,0 +1,39 @@ +-- DB update 2026_04_25_01 -> 2026_04_25_02 +-- Update Apothecary Ravien SmartAI +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 23782; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 23782); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(23782, 0, 0, 0, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 1, 23782, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Just Summoned - Start Waypoint Path 23782'), +(23782, 0, 1, 2, 40, 0, 100, 512, 6, 23782, 0, 0, 0, 0, 54, 60000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Point 6 of Path 23782 Reached - Pause Waypoint'), +(23782, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 10, 101906, 24126, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Point 6 of Path 23782 Reached - Set Orientation Closest Creature \'Apothecary Lysander\''), +(23782, 0, 3, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 223, 10, 0, 0, 0, 0, 0, 10, 101906, 24126, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Point 6 of Path 23782 Reached - Do Action ID 10'), +(23782, 0, 4, 0, 40, 0, 100, 512, 7, 23782, 0, 0, 0, 0, 223, 11, 0, 0, 0, 0, 0, 10, 101906, 24126, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Point 7 of Path 23782 Reached - Do Action ID 11'), +(23782, 0, 5, 0, 40, 0, 100, 512, 18, 23782, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Ravien - On Point 18 of Path 23782 Reached - Despawn Instant'); + +-- Update Apothecary Lysander SmartAI +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 24126; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24126); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(24126, 0, 0, 0, 20, 1, 100, 0, 11170, 0, 0, 0, 0, 0, 80, 2412600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - On Quest \'Test at Sea\' Finished - Run Script (Phase 1)'), +(24126, 0, 1, 0, 72, 0, 100, 0, 10, 0, 0, 0, 0, 0, 80, 2412601, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - On Action 10 Done - Run Script'), +(24126, 0, 2, 0, 72, 0, 100, 0, 11, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - On Action 11 Done - Set Event Phase 1'), +(24126, 0, 3, 0, 1, 1, 100, 0, 0, 30000, 30000, 90000, 0, 0, 1, 6, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Out of Combat - Say Line 6 (Phase 1)'), +(24126, 0, 4, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - On Reset - Set Event Phase 1'); + +-- Set Action Lists +DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (2412600, 2412601)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2412600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 12, 23782, 1, 90000, 0, 0, 0, 8, 0, 0, 0, 0, 1965.13, -6126.74, 25.6126, 3.27167, 'Apothecary Lysander - Actionlist - Summon Creature \'Apothecary Ravien\''), +(2412600, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Set Event Phase 0'), +(2412601, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 23782, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 0 (Apothecary Ravien)'), +(2412601, 9, 1, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 0'), +(2412601, 9, 2, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 204, 23782, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 1 (Apothecary Ravien)'), +(2412601, 9, 3, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 1'), +(2412601, 9, 4, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 204, 23782, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 2 (Apothecary Ravien)'), +(2412601, 9, 5, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 2'), +(2412601, 9, 6, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 3'), +(2412601, 9, 7, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 4'), +(2412601, 9, 8, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 5'), +(2412601, 9, 9, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 204, 23782, 0, 0, 0, 0, 0, 0, 0, 'Apothecary Lysander - Actionlist - Say Line 3 (Apothecary Ravien)'); diff --git a/data/sql/updates/db_world/2026_04_25_03.sql b/data/sql/updates/db_world/2026_04_25_03.sql new file mode 100644 index 000000000..09fc17a08 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_25_03.sql @@ -0,0 +1,5 @@ +-- DB update 2026_04_25_02 -> 2026_04_25_03 +-- +-- Remove AoE spell cast to entry, that may sometimes not be in range. +DELETE FROM `waypoint_scripts` WHERE `id` IN (488, 489, 490) AND `guid` IN (891, 892, 893); +UPDATE `waypoint_data` SET `action` = 0 WHERE `id` = 1365540 AND `point` IN (4, 10, 18); diff --git a/data/sql/updates/db_world/2026_04_25_04.sql b/data/sql/updates/db_world/2026_04_25_04.sql new file mode 100644 index 000000000..2412b984c --- /dev/null +++ b/data/sql/updates/db_world/2026_04_25_04.sql @@ -0,0 +1,22 @@ +-- DB update 2026_04_25_03 -> 2026_04_25_04 + +-- Update General SAI. +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28511; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28511) AND (`source_type` = 0) AND (`id` IN (3, 4)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28511, 0, 3, 0, 108, 0, 100, 512, 3, 2851100, 0, 0, 0, 0, 80, 2851101, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Point 3 of Path 2851100 Reached - Run Script'), +(28511, 0, 4, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 51852, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Just Died - Remove Aura \'The Eye of Acherus\''); + +-- Delete Action List rows (they are moved on new Action List). +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2851100) AND (`source_type` = 9) AND (`id` IN (5, 6, 7, 8, 9, 10)); + +-- Create new Action List. +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2851101) AND (`source_type` = 0); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2851101, 9, 0, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Set Rooted On'), +(2851101, 9, 1, 0, 0, 0, 100, 512, 500, 500, 0, 0, 0, 0, 11, 51890, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Cast \'Eye of Acherus Flight\''), +(2851101, 9, 2, 0, 0, 0, 100, 512, 500, 500, 0, 0, 0, 0, 28, 51923, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Remove Aura \'Eye of Acherus Flight (Boost)\''), +(2851101, 9, 3, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 28, 51860, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Remove Aura \'Serverside - Root Self\''), +(2851101, 9, 4, 0, 0, 0, 100, 512, 500, 500, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Say Line 1'), +(2851101, 9, 5, 0, 0, 0, 100, 512, 500, 500, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Set Rooted Off'); diff --git a/data/sql/updates/db_world/2026_04_26_00.sql b/data/sql/updates/db_world/2026_04_26_00.sql new file mode 100644 index 000000000..b5dddbd04 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_00.sql @@ -0,0 +1,5 @@ +-- DB update 2026_04_25_04 -> 2026_04_26_00 +DELETE FROM `smart_scripts` +WHERE `entryorguid` IN (2397400, 2397401, 2397402, 2397403) + AND `source_type` = 9 + AND `id` = 1; diff --git a/data/sql/updates/db_world/2026_04_26_01.sql b/data/sql/updates/db_world/2026_04_26_01.sql new file mode 100644 index 000000000..a9fe420d1 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_01.sql @@ -0,0 +1,24 @@ +-- DB update 2026_04_26_00 -> 2026_04_26_01 +-- +DELETE FROM `npc_vendor` WHERE (`entry` = 35642) AND (`item` IN (3775, 43231, 43233, 43235, 43237)); +INSERT INTO `npc_vendor` (`entry`, `slot`, `item`, `maxcount`, `incrtime`, `ExtendedCost`, `VerifiedBuild`) VALUES +(35642, 0, 3775, 0, 0, 0, 0), +(35642, 0, 43231, 0, 0, 0, 0), +(35642, 0, 43233, 0, 0, 0, 0), +(35642, 0, 43235, 0, 0, 0, 0), +(35642, 0, 43237, 0, 0, 0, 0); + +DELETE FROM `npc_vendor` WHERE (`entry` = 29561) AND (`item` IN (5565, 16583, 17020, 17030, 17031, 17032, 17033, 37201, 44605, 44614, 44615)); +INSERT INTO `npc_vendor` (`entry`, `slot`, `item`, `maxcount`, `incrtime`, `ExtendedCost`, `VerifiedBuild`) VALUES +(29561, 0, 5565, 5, 600, 0, 0), +(29561, 0, 16583, 2, 600, 0, 0), +(29561, 0, 17020, 80, 600, 0, 0), +(29561, 0, 17030, 10, 600, 0, 0), +(29561, 0, 17031, 10, 600, 0, 0), +(29561, 0, 17032, 4, 600, 0, 0), +(29561, 0, 17033, 10, 600, 0, 0), +-- (29561, 0, 21177, 300, 600, 0, 0), -- fixed in 36a1f31c2911e312a894c7a02027b98c1af79dbc +(29561, 0, 37201, 40, 600, 0, 0), +(29561, 0, 44605, 55, 600, 0, 0), +(29561, 0, 44614, 20, 600, 0, 0), +(29561, 0, 44615, 55, 600, 0, 0); diff --git a/data/sql/updates/db_world/2026_04_26_02.sql b/data/sql/updates/db_world/2026_04_26_02.sql new file mode 100644 index 000000000..2ae742cd8 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_02.sql @@ -0,0 +1,15 @@ +-- DB update 2026_04_26_01 -> 2026_04_26_02 + +-- Update Mogor SAI +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 18069; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 18069) AND (`source_type` = 0) AND (`id` IN (7, 9, 11)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(18069, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mogor - On Evade - Despawn Instant - Failure Event'), +(18069, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mogor - On Just Died - Despawn In 5000 ms'), +(18069, 0, 11, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 82, 2, 0, 0, 0, 0, 0, 10, 66480, 18471, 0, 0, 0, 0, 0, 0, 'Mogor - On Respawn - Add Npc Flags Questgiver'); + +-- Update Gurgthock Action List +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1847117) AND (`source_type` = 9) AND (`id` IN (1, 2)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(1847117, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 6, 9977, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 0, 0, 0, 0, 'Gurgthock - Mogor Failure Script - Fail Quest \'The Ring of Blood: The Final Challenge\''); diff --git a/data/sql/updates/db_world/2026_04_26_03.sql b/data/sql/updates/db_world/2026_04_26_03.sql new file mode 100644 index 000000000..79c4ce2be --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_03.sql @@ -0,0 +1,40 @@ +-- DB update 2026_04_26_02 -> 2026_04_26_03 + +-- Wipe creature_template_movement. +DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 28511); + +-- Delete old waypoint. +DELETE FROM `waypoint_data` WHERE (`id` IN (2851100)); + +-- Add new waypoint. +DELETE FROM `waypoints` WHERE `entry` IN (2851100); +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `point_comment`) VALUES +(2851100, 1, 2341.57, -5672.8, 538.394, NULL, 'Eye of Acherus Flight'), +(2851100, 2, 1957.4, -5844.11, 273.867, NULL, 'Eye of Acherus Flight'), +(2851100, 3, 1758.01, -5876.78, 166.867, NULL, 'Eye of Acherus Flight'); + +-- Edit SAI. +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28511; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28511); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28511, 0, 0, 1, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Just Summoned - Set Rooted On'), +(28511, 0, 1, 2, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 51860, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Just Summoned - Cast \'Serverside - Root Self\''), +(28511, 0, 2, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2851100, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Just Summoned - Run Script'), +(28511, 0, 3, 0, 40, 0, 100, 512, 3, 2851100, 0, 0, 0, 0, 80, 2851101, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Point 3 of Path 2851100 Reached - Run Script'), +(28511, 0, 4, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 51852, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - On Just Died - Remove Aura \'The Eye of Acherus\''); + +-- Edit Timed Action Lists +DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (2851100, 2851101)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2851100, 9, 0, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 51892, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Cast \'Eye of Acherus Visual\''), +(2851100, 9, 1, 0, 0, 0, 100, 512, 6000, 6000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Say Line 0'), +(2851100, 9, 2, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 51923, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Cast \'Eye of Acherus Flight (Boost)\''), +(2851100, 9, 3, 0, 0, 0, 100, 512, 1000, 1000, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Set Rooted Off'), +(2851100, 9, 4, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 2, 2851100, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Start Waypoint Path 2851100'), +(2851101, 9, 0, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Set Rooted On'), +(2851101, 9, 1, 0, 0, 0, 100, 512, 1000, 1000, 0, 0, 0, 0, 11, 51890, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Cast \'Eye of Acherus Flight\''), +(2851101, 9, 2, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 51923, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Remove Aura \'Eye of Acherus Flight (Boost)\''), +(2851101, 9, 3, 0, 0, 0, 100, 512, 1000, 1000, 0, 0, 0, 0, 28, 51860, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Remove Aura \'Serverside - Root Self\''), +(2851101, 9, 4, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Say Line 1'), +(2851101, 9, 5, 0, 0, 0, 100, 512, 1000, 1000, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Eye of Acherus - Actionlist - Set Rooted Off'); diff --git a/data/sql/updates/db_world/2026_04_26_04.sql b/data/sql/updates/db_world/2026_04_26_04.sql new file mode 100644 index 000000000..18a1d166c --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_04.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_26_03 -> 2026_04_26_04 +-- +UPDATE `instance_encounters` SET `creditEntry`=16152 WHERE `entry`=652; diff --git a/data/sql/updates/db_world/2026_04_26_05.sql b/data/sql/updates/db_world/2026_04_26_05.sql new file mode 100644 index 000000000..e63154c66 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_26_05.sql @@ -0,0 +1,469 @@ +-- DB update 2026_04_26_04 -> 2026_04_26_05 +-- Adds missing items to vendors, corrects rating requirements and arena point+honour costs. +DELETE FROM `npc_vendor` WHERE (`entry` IN (33915, 33918, 33921, 34087, 34088, 34089)); +INSERT INTO `npc_vendor` (`entry`, `slot`, `item`, `maxcount`, `incrtime`, `ExtendedCost`, `VerifiedBuild`) VALUES +(33915, 0, 40787, 0, 0, 2622, 0), +(33915, 0, 40788, 0, 0, 2622, 0), +(33915, 0, 40789, 0, 0, 2622, 0), +(33915, 0, 40807, 0, 0, 2621, 0), +(33915, 0, 40808, 0, 0, 2621, 0), +(33915, 0, 40809, 0, 0, 2621, 0), +(33915, 0, 40826, 0, 0, 2629, 0), +(33915, 0, 40827, 0, 0, 2629, 0), +(33915, 0, 40828, 0, 0, 2629, 0), +(33915, 0, 40847, 0, 0, 2340, 0), +(33915, 0, 40848, 0, 0, 2340, 0), +(33915, 0, 40849, 0, 0, 2340, 0), +(33915, 0, 40866, 0, 0, 2470, 0), +(33915, 0, 40868, 0, 0, 2470, 0), +(33915, 0, 40869, 0, 0, 2470, 0), +(33915, 0, 40907, 0, 0, 2622, 0), +(33915, 0, 40927, 0, 0, 2621, 0), +(33915, 0, 40933, 0, 0, 2629, 0), +(33915, 0, 40939, 0, 0, 2340, 0), +(33915, 0, 40963, 0, 0, 2470, 0), +(33915, 0, 40992, 0, 0, 2622, 0), +(33915, 0, 40993, 0, 0, 2622, 0), +(33915, 0, 41001, 0, 0, 2621, 0), +(33915, 0, 41007, 0, 0, 2621, 0), +(33915, 0, 41013, 0, 0, 2629, 0), +(33915, 0, 41019, 0, 0, 2629, 0), +(33915, 0, 41027, 0, 0, 2340, 0), +(33915, 0, 41033, 0, 0, 2340, 0), +(33915, 0, 41038, 0, 0, 2470, 0), +(33915, 0, 41044, 0, 0, 2470, 0), +(33915, 0, 41081, 0, 0, 2622, 0), +(33915, 0, 41087, 0, 0, 2622, 0), +(33915, 0, 41137, 0, 0, 2621, 0), +(33915, 0, 41143, 0, 0, 2621, 0), +(33915, 0, 41151, 0, 0, 2629, 0), +(33915, 0, 41157, 0, 0, 2629, 0), +(33915, 0, 41199, 0, 0, 2340, 0), +(33915, 0, 41205, 0, 0, 2340, 0), +(33915, 0, 41211, 0, 0, 2470, 0), +(33915, 0, 41217, 0, 0, 2470, 0), +(33915, 0, 41275, 0, 0, 2470, 0), +(33915, 0, 41281, 0, 0, 2470, 0), +(33915, 0, 41287, 0, 0, 2621, 0), +(33915, 0, 41293, 0, 0, 2621, 0), +(33915, 0, 41298, 0, 0, 2340, 0), +(33915, 0, 41304, 0, 0, 2340, 0), +(33915, 0, 41310, 0, 0, 2622, 0), +(33915, 0, 41316, 0, 0, 2622, 0), +(33915, 0, 41321, 0, 0, 2629, 0), +(33915, 0, 41327, 0, 0, 2629, 0), +(33915, 0, 41650, 0, 0, 2622, 0), +(33915, 0, 41655, 0, 0, 2340, 0), +(33915, 0, 41661, 0, 0, 2622, 0), +(33915, 0, 41667, 0, 0, 2340, 0), +(33915, 0, 41672, 0, 0, 2629, 0), +(33915, 0, 41678, 0, 0, 2629, 0), +(33915, 0, 41683, 0, 0, 2470, 0), +(33915, 0, 41715, 0, 0, 2470, 0), +(33915, 0, 41767, 0, 0, 2621, 0), +(33915, 0, 41773, 0, 0, 2621, 0), +(33915, 0, 41854, 0, 0, 2629, 0), +(33915, 0, 41859, 0, 0, 2622, 0), +(33915, 0, 41864, 0, 0, 2340, 0), +(33915, 0, 41869, 0, 0, 2470, 0), +(33915, 0, 41874, 0, 0, 2621, 0), +(33915, 0, 41915, 0, 0, 2629, 0), +(33915, 0, 41921, 0, 0, 2622, 0), +(33915, 0, 41927, 0, 0, 2340, 0), +(33915, 0, 41934, 0, 0, 2470, 0), +(33915, 0, 41940, 0, 0, 2621, 0), +(33915, 0, 41946, 0, 0, 2629, 0), +(33915, 0, 41953, 0, 0, 2622, 0), +(33915, 0, 41959, 0, 0, 2340, 0), +(33915, 0, 41965, 0, 0, 2470, 0), +(33915, 0, 41971, 0, 0, 2621, 0), +(33915, 0, 41993, 0, 0, 2629, 0), +(33915, 0, 41998, 0, 0, 2622, 0), +(33915, 0, 42005, 0, 0, 2340, 0), +(33915, 0, 42011, 0, 0, 2470, 0), +(33915, 0, 42017, 0, 0, 2621, 0), +(33915, 0, 42209, 0, 0, 2624, 0), +(33915, 0, 42228, 0, 0, 2721, 0), +(33915, 0, 42233, 0, 0, 2721, 0), +(33915, 0, 42243, 0, 0, 2624, 0), +(33915, 0, 42249, 0, 0, 2721, 0), +(33915, 0, 42256, 0, 0, 2721, 0), +(33915, 0, 42261, 0, 0, 2624, 0), +(33915, 0, 42266, 0, 0, 2721, 0), +(33915, 0, 42271, 0, 0, 2721, 0), +(33915, 0, 42276, 0, 0, 2624, 0), +(33915, 0, 42281, 0, 0, 2721, 0), +(33915, 0, 42286, 0, 0, 2624, 0), +(33915, 0, 42291, 0, 0, 2721, 0), +(33915, 0, 42318, 0, 0, 2623, 0), +(33915, 0, 42323, 0, 0, 2623, 0), +(33915, 0, 42328, 0, 0, 2623, 0), +(33915, 0, 42333, 0, 0, 2623, 0), +(33915, 0, 42347, 0, 0, 2624, 0), +(33915, 0, 42353, 0, 0, 2624, 0), +(33915, 0, 42364, 0, 0, 2623, 0), +(33915, 0, 42385, 0, 0, 2623, 0), +(33915, 0, 42391, 0, 0, 2623, 0), +(33915, 0, 42451, 0, 0, 2384, 0), +(33915, 0, 42486, 0, 0, 2623, 0), +(33915, 0, 42491, 0, 0, 2623, 0), +(33915, 0, 42496, 0, 0, 2623, 0), +(33915, 0, 42503, 0, 0, 2384, 0), +(33915, 0, 42514, 0, 0, 2384, 0), +(33915, 0, 42520, 0, 0, 2384, 0), +(33915, 0, 42526, 0, 0, 2721, 0), +(33915, 0, 42532, 0, 0, 2721, 0), +(33915, 0, 42538, 0, 0, 2721, 0), +(33915, 0, 42560, 0, 0, 2628, 0), +(33915, 0, 42565, 0, 0, 2628, 0), +(33915, 0, 42571, 0, 0, 2628, 0), +(33915, 0, 42579, 0, 0, 2384, 0), +(33915, 0, 42584, 0, 0, 2384, 0), +(33915, 0, 42589, 0, 0, 2384, 0), +(33915, 0, 42598, 0, 0, 2384, 0), +(33915, 0, 42603, 0, 0, 2384, 0), +(33915, 0, 42608, 0, 0, 2384, 0), +(33915, 0, 42615, 0, 0, 2384, 0), +(33915, 0, 42621, 0, 0, 2384, 0), +(33915, 0, 42853, 0, 0, 2384, 0), +(33915, 0, 44421, 0, 0, 2623, 0), +(33915, 0, 44422, 0, 0, 2623, 0), +(33915, 0, 45706, 0, 0, 2596, 0), +(33915, 0, 45983, 0, 0, 2636, 0), +(33918, 0, 40787, 0, 0, 2622, 0), +(33918, 0, 40788, 0, 0, 2622, 0), +(33918, 0, 40789, 0, 0, 2622, 0), +(33918, 0, 40807, 0, 0, 2621, 0), +(33918, 0, 40808, 0, 0, 2621, 0), +(33918, 0, 40809, 0, 0, 2621, 0), +(33918, 0, 40826, 0, 0, 2629, 0), +(33918, 0, 40827, 0, 0, 2629, 0), +(33918, 0, 40828, 0, 0, 2629, 0), +(33918, 0, 40847, 0, 0, 2340, 0), +(33918, 0, 40848, 0, 0, 2340, 0), +(33918, 0, 40849, 0, 0, 2340, 0), +(33918, 0, 40866, 0, 0, 2470, 0), +(33918, 0, 40868, 0, 0, 2470, 0), +(33918, 0, 40869, 0, 0, 2470, 0), +(33918, 0, 40907, 0, 0, 2622, 0), +(33918, 0, 40927, 0, 0, 2621, 0), +(33918, 0, 40933, 0, 0, 2629, 0), +(33918, 0, 40939, 0, 0, 2340, 0), +(33918, 0, 40963, 0, 0, 2470, 0), +(33918, 0, 40992, 0, 0, 2622, 0), +(33918, 0, 40993, 0, 0, 2622, 0), +(33918, 0, 41001, 0, 0, 2621, 0), +(33918, 0, 41007, 0, 0, 2621, 0), +(33918, 0, 41013, 0, 0, 2629, 0), +(33918, 0, 41019, 0, 0, 2629, 0), +(33918, 0, 41027, 0, 0, 2340, 0), +(33918, 0, 41033, 0, 0, 2340, 0), +(33918, 0, 41038, 0, 0, 2470, 0), +(33918, 0, 41044, 0, 0, 2470, 0), +(33918, 0, 41081, 0, 0, 2622, 0), +(33918, 0, 41087, 0, 0, 2622, 0), +(33918, 0, 41137, 0, 0, 2621, 0), +(33918, 0, 41143, 0, 0, 2621, 0), +(33918, 0, 41151, 0, 0, 2629, 0), +(33918, 0, 41157, 0, 0, 2629, 0), +(33918, 0, 41199, 0, 0, 2340, 0), +(33918, 0, 41205, 0, 0, 2340, 0), +(33918, 0, 41211, 0, 0, 2470, 0), +(33918, 0, 41217, 0, 0, 2470, 0), +(33918, 0, 41275, 0, 0, 2470, 0), +(33918, 0, 41281, 0, 0, 2470, 0), +(33918, 0, 41287, 0, 0, 2621, 0), +(33918, 0, 41293, 0, 0, 2621, 0), +(33918, 0, 41298, 0, 0, 2340, 0), +(33918, 0, 41304, 0, 0, 2340, 0), +(33918, 0, 41310, 0, 0, 2622, 0), +(33918, 0, 41316, 0, 0, 2622, 0), +(33918, 0, 41321, 0, 0, 2629, 0), +(33918, 0, 41327, 0, 0, 2629, 0), +(33918, 0, 41650, 0, 0, 2622, 0), +(33918, 0, 41655, 0, 0, 2340, 0), +(33918, 0, 41661, 0, 0, 2622, 0), +(33918, 0, 41667, 0, 0, 2340, 0), +(33918, 0, 41672, 0, 0, 2629, 0), +(33918, 0, 41678, 0, 0, 2629, 0), +(33918, 0, 41683, 0, 0, 2470, 0), +(33918, 0, 41715, 0, 0, 2470, 0), +(33918, 0, 41767, 0, 0, 2621, 0), +(33918, 0, 41773, 0, 0, 2621, 0), +(33918, 0, 41854, 0, 0, 2629, 0), +(33918, 0, 41859, 0, 0, 2622, 0), +(33918, 0, 41864, 0, 0, 2340, 0), +(33918, 0, 41869, 0, 0, 2470, 0), +(33918, 0, 41874, 0, 0, 2621, 0), +(33918, 0, 41915, 0, 0, 2629, 0), +(33918, 0, 41921, 0, 0, 2622, 0), +(33918, 0, 41927, 0, 0, 2340, 0), +(33918, 0, 41934, 0, 0, 2470, 0), +(33918, 0, 41940, 0, 0, 2621, 0), +(33918, 0, 41946, 0, 0, 2629, 0), +(33918, 0, 41953, 0, 0, 2622, 0), +(33918, 0, 41959, 0, 0, 2340, 0), +(33918, 0, 41965, 0, 0, 2470, 0), +(33918, 0, 41971, 0, 0, 2621, 0), +(33918, 0, 41993, 0, 0, 2629, 0), +(33918, 0, 41998, 0, 0, 2622, 0), +(33918, 0, 42005, 0, 0, 2340, 0), +(33918, 0, 42011, 0, 0, 2470, 0), +(33918, 0, 42017, 0, 0, 2621, 0), +(33918, 0, 42209, 0, 0, 2624, 0), +(33918, 0, 42228, 0, 0, 2721, 0), +(33918, 0, 42233, 0, 0, 2721, 0), +(33918, 0, 42243, 0, 0, 2624, 0), +(33918, 0, 42249, 0, 0, 2721, 0), +(33918, 0, 42256, 0, 0, 2721, 0), +(33918, 0, 42261, 0, 0, 2624, 0), +(33918, 0, 42266, 0, 0, 2721, 0), +(33918, 0, 42271, 0, 0, 2721, 0), +(33918, 0, 42276, 0, 0, 2624, 0), +(33918, 0, 42281, 0, 0, 2721, 0), +(33918, 0, 42286, 0, 0, 2624, 0), +(33918, 0, 42291, 0, 0, 2721, 0), +(33918, 0, 42318, 0, 0, 2623, 0), +(33918, 0, 42323, 0, 0, 2623, 0), +(33918, 0, 42328, 0, 0, 2623, 0), +(33918, 0, 42333, 0, 0, 2623, 0), +(33918, 0, 42347, 0, 0, 2624, 0), +(33918, 0, 42353, 0, 0, 2624, 0), +(33918, 0, 42364, 0, 0, 2623, 0), +(33918, 0, 42385, 0, 0, 2623, 0), +(33918, 0, 42391, 0, 0, 2623, 0), +(33918, 0, 42451, 0, 0, 2384, 0), +(33918, 0, 42486, 0, 0, 2623, 0), +(33918, 0, 42491, 0, 0, 2623, 0), +(33918, 0, 42496, 0, 0, 2623, 0), +(33918, 0, 42503, 0, 0, 2384, 0), +(33918, 0, 42514, 0, 0, 2384, 0), +(33918, 0, 42520, 0, 0, 2384, 0), +(33918, 0, 42526, 0, 0, 2721, 0), +(33918, 0, 42532, 0, 0, 2721, 0), +(33918, 0, 42538, 0, 0, 2721, 0), +(33918, 0, 42560, 0, 0, 2628, 0), +(33918, 0, 42565, 0, 0, 2628, 0), +(33918, 0, 42571, 0, 0, 2628, 0), +(33918, 0, 42579, 0, 0, 2384, 0), +(33918, 0, 42584, 0, 0, 2384, 0), +(33918, 0, 42589, 0, 0, 2384, 0), +(33918, 0, 42598, 0, 0, 2384, 0), +(33918, 0, 42603, 0, 0, 2384, 0), +(33918, 0, 42608, 0, 0, 2384, 0), +(33918, 0, 42615, 0, 0, 2384, 0), +(33918, 0, 42621, 0, 0, 2384, 0), +(33918, 0, 42853, 0, 0, 2384, 0), +(33918, 0, 44421, 0, 0, 2623, 0), +(33918, 0, 44422, 0, 0, 2623, 0), +(33918, 0, 45706, 0, 0, 2596, 0), +(33918, 0, 45983, 0, 0, 2636, 0), +(33921, 0, 40787, 0, 0, 2622, 0), +(33921, 0, 40788, 0, 0, 2622, 0), +(33921, 0, 40789, 0, 0, 2622, 0), +(33921, 0, 40807, 0, 0, 2621, 0), +(33921, 0, 40808, 0, 0, 2621, 0), +(33921, 0, 40809, 0, 0, 2621, 0), +(33921, 0, 40826, 0, 0, 2629, 0), +(33921, 0, 40827, 0, 0, 2629, 0), +(33921, 0, 40828, 0, 0, 2629, 0), +(33921, 0, 40847, 0, 0, 2340, 0), +(33921, 0, 40848, 0, 0, 2340, 0), +(33921, 0, 40849, 0, 0, 2340, 0), +(33921, 0, 40866, 0, 0, 2470, 0), +(33921, 0, 40868, 0, 0, 2470, 0), +(33921, 0, 40869, 0, 0, 2470, 0), +(33921, 0, 40907, 0, 0, 2622, 0), +(33921, 0, 40927, 0, 0, 2621, 0), +(33921, 0, 40933, 0, 0, 2629, 0), +(33921, 0, 40939, 0, 0, 2340, 0), +(33921, 0, 40963, 0, 0, 2470, 0), +(33921, 0, 40992, 0, 0, 2622, 0), +(33921, 0, 40993, 0, 0, 2622, 0), +(33921, 0, 41001, 0, 0, 2621, 0), +(33921, 0, 41007, 0, 0, 2621, 0), +(33921, 0, 41013, 0, 0, 2629, 0), +(33921, 0, 41019, 0, 0, 2629, 0), +(33921, 0, 41027, 0, 0, 2340, 0), +(33921, 0, 41033, 0, 0, 2340, 0), +(33921, 0, 41038, 0, 0, 2470, 0), +(33921, 0, 41044, 0, 0, 2470, 0), +(33921, 0, 41081, 0, 0, 2622, 0), +(33921, 0, 41087, 0, 0, 2622, 0), +(33921, 0, 41137, 0, 0, 2621, 0), +(33921, 0, 41143, 0, 0, 2621, 0), +(33921, 0, 41151, 0, 0, 2629, 0), +(33921, 0, 41157, 0, 0, 2629, 0), +(33921, 0, 41199, 0, 0, 2340, 0), +(33921, 0, 41205, 0, 0, 2340, 0), +(33921, 0, 41211, 0, 0, 2470, 0), +(33921, 0, 41217, 0, 0, 2470, 0), +(33921, 0, 41275, 0, 0, 2470, 0), +(33921, 0, 41281, 0, 0, 2470, 0), +(33921, 0, 41287, 0, 0, 2621, 0), +(33921, 0, 41293, 0, 0, 2621, 0), +(33921, 0, 41298, 0, 0, 2340, 0), +(33921, 0, 41304, 0, 0, 2340, 0), +(33921, 0, 41310, 0, 0, 2622, 0), +(33921, 0, 41316, 0, 0, 2622, 0), +(33921, 0, 41321, 0, 0, 2629, 0), +(33921, 0, 41327, 0, 0, 2629, 0), +(33921, 0, 41650, 0, 0, 2622, 0), +(33921, 0, 41655, 0, 0, 2340, 0), +(33921, 0, 41661, 0, 0, 2622, 0), +(33921, 0, 41667, 0, 0, 2340, 0), +(33921, 0, 41672, 0, 0, 2629, 0), +(33921, 0, 41678, 0, 0, 2629, 0), +(33921, 0, 41683, 0, 0, 2470, 0), +(33921, 0, 41715, 0, 0, 2470, 0), +(33921, 0, 41767, 0, 0, 2621, 0), +(33921, 0, 41773, 0, 0, 2621, 0), +(33921, 0, 41854, 0, 0, 2629, 0), +(33921, 0, 41859, 0, 0, 2622, 0), +(33921, 0, 41864, 0, 0, 2340, 0), +(33921, 0, 41869, 0, 0, 2470, 0), +(33921, 0, 41874, 0, 0, 2621, 0), +(33921, 0, 41915, 0, 0, 2629, 0), +(33921, 0, 41921, 0, 0, 2622, 0), +(33921, 0, 41927, 0, 0, 2340, 0), +(33921, 0, 41934, 0, 0, 2470, 0), +(33921, 0, 41940, 0, 0, 2621, 0), +(33921, 0, 41946, 0, 0, 2629, 0), +(33921, 0, 41953, 0, 0, 2622, 0), +(33921, 0, 41959, 0, 0, 2340, 0), +(33921, 0, 41965, 0, 0, 2470, 0), +(33921, 0, 41971, 0, 0, 2621, 0), +(33921, 0, 41993, 0, 0, 2629, 0), +(33921, 0, 41998, 0, 0, 2622, 0), +(33921, 0, 42005, 0, 0, 2340, 0), +(33921, 0, 42011, 0, 0, 2470, 0), +(33921, 0, 42017, 0, 0, 2621, 0), +(33921, 0, 42209, 0, 0, 2624, 0), +(33921, 0, 42228, 0, 0, 2721, 0), +(33921, 0, 42233, 0, 0, 2721, 0), +(33921, 0, 42243, 0, 0, 2624, 0), +(33921, 0, 42249, 0, 0, 2721, 0), +(33921, 0, 42256, 0, 0, 2721, 0), +(33921, 0, 42261, 0, 0, 2624, 0), +(33921, 0, 42266, 0, 0, 2721, 0), +(33921, 0, 42271, 0, 0, 2721, 0), +(33921, 0, 42276, 0, 0, 2624, 0), +(33921, 0, 42281, 0, 0, 2721, 0), +(33921, 0, 42286, 0, 0, 2624, 0), +(33921, 0, 42291, 0, 0, 2721, 0), +(33921, 0, 42318, 0, 0, 2623, 0), +(33921, 0, 42323, 0, 0, 2623, 0), +(33921, 0, 42328, 0, 0, 2623, 0), +(33921, 0, 42333, 0, 0, 2623, 0), +(33921, 0, 42347, 0, 0, 2624, 0), +(33921, 0, 42353, 0, 0, 2624, 0), +(33921, 0, 42364, 0, 0, 2623, 0), +(33921, 0, 42385, 0, 0, 2623, 0), +(33921, 0, 42391, 0, 0, 2623, 0), +(33921, 0, 42451, 0, 0, 2384, 0), +(33921, 0, 42486, 0, 0, 2623, 0), +(33921, 0, 42491, 0, 0, 2623, 0), +(33921, 0, 42496, 0, 0, 2623, 0), +(33921, 0, 42503, 0, 0, 2384, 0), +(33921, 0, 42514, 0, 0, 2384, 0), +(33921, 0, 42520, 0, 0, 2384, 0), +(33921, 0, 42526, 0, 0, 2721, 0), +(33921, 0, 42532, 0, 0, 2721, 0), +(33921, 0, 42538, 0, 0, 2721, 0), +(33921, 0, 42560, 0, 0, 2628, 0), +(33921, 0, 42565, 0, 0, 2628, 0), +(33921, 0, 42571, 0, 0, 2628, 0), +(33921, 0, 42579, 0, 0, 2384, 0), +(33921, 0, 42584, 0, 0, 2384, 0), +(33921, 0, 42589, 0, 0, 2384, 0), +(33921, 0, 42598, 0, 0, 2384, 0), +(33921, 0, 42603, 0, 0, 2384, 0), +(33921, 0, 42608, 0, 0, 2384, 0), +(33921, 0, 42615, 0, 0, 2384, 0), +(33921, 0, 42621, 0, 0, 2384, 0), +(33921, 0, 42853, 0, 0, 2384, 0), +(33921, 0, 44421, 0, 0, 2623, 0), +(33921, 0, 44422, 0, 0, 2623, 0), +(33921, 0, 45706, 0, 0, 2596, 0), +(33921, 0, 45983, 0, 0, 2636, 0), +(34087, 0, 45937, 0, 0, 2632, 0), +(34087, 0, 45938, 0, 0, 2632, 0), +(34087, 0, 45939, 0, 0, 2632, 0), +(34087, 0, 45948, 0, 0, 2632, 0), +(34087, 0, 45949, 0, 0, 2632, 0), +(34087, 0, 45950, 0, 0, 2632, 0), +(34087, 0, 45951, 0, 0, 2632, 0), +(34087, 0, 45952, 0, 0, 2632, 0), +(34087, 0, 45953, 0, 0, 2632, 0), +(34087, 0, 45954, 0, 0, 2632, 0), +(34087, 0, 45955, 0, 0, 2632, 0), +(34087, 0, 45956, 0, 0, 2632, 0), +(34087, 0, 45957, 0, 0, 2634, 0), +(34087, 0, 45958, 0, 0, 2634, 0), +(34087, 0, 45959, 0, 0, 2634, 0), +(34087, 0, 45960, 0, 0, 2634, 0), +(34087, 0, 45961, 0, 0, 2635, 0), +(34087, 0, 45962, 0, 0, 2635, 0), +(34087, 0, 45963, 0, 0, 2635, 0), +(34087, 0, 45964, 0, 0, 2635, 0), +(34087, 0, 45965, 0, 0, 2635, 0), +(34087, 0, 45966, 0, 0, 2635, 0), +(34087, 0, 45967, 0, 0, 2635, 0), +(34087, 0, 45968, 0, 0, 2635, 0), +(34087, 0, 45969, 0, 0, 2634, 0), +(34087, 0, 45970, 0, 0, 2633, 0), +(34087, 0, 45971, 0, 0, 2633, 0), +(34088, 0, 45937, 0, 0, 2632, 0), +(34088, 0, 45938, 0, 0, 2632, 0), +(34088, 0, 45939, 0, 0, 2632, 0), +(34088, 0, 45948, 0, 0, 2632, 0), +(34088, 0, 45949, 0, 0, 2632, 0), +(34088, 0, 45950, 0, 0, 2632, 0), +(34088, 0, 45951, 0, 0, 2632, 0), +(34088, 0, 45952, 0, 0, 2632, 0), +(34088, 0, 45953, 0, 0, 2632, 0), +(34088, 0, 45954, 0, 0, 2632, 0), +(34088, 0, 45955, 0, 0, 2632, 0), +(34088, 0, 45956, 0, 0, 2632, 0), +(34088, 0, 45957, 0, 0, 2634, 0), +(34088, 0, 45958, 0, 0, 2634, 0), +(34088, 0, 45959, 0, 0, 2634, 0), +(34088, 0, 45960, 0, 0, 2634, 0), +(34088, 0, 45961, 0, 0, 2635, 0), +(34088, 0, 45962, 0, 0, 2635, 0), +(34088, 0, 45963, 0, 0, 2635, 0), +(34088, 0, 45964, 0, 0, 2635, 0), +(34088, 0, 45965, 0, 0, 2635, 0), +(34088, 0, 45966, 0, 0, 2635, 0), +(34088, 0, 45967, 0, 0, 2635, 0), +(34088, 0, 45968, 0, 0, 2635, 0), +(34088, 0, 45969, 0, 0, 2634, 0), +(34088, 0, 45970, 0, 0, 2633, 0), +(34088, 0, 45971, 0, 0, 2633, 0), +(34089, 0, 45937, 0, 0, 2632, 0), +(34089, 0, 45938, 0, 0, 2632, 0), +(34089, 0, 45939, 0, 0, 2632, 0), +(34089, 0, 45948, 0, 0, 2632, 0), +(34089, 0, 45949, 0, 0, 2632, 0), +(34089, 0, 45950, 0, 0, 2632, 0), +(34089, 0, 45951, 0, 0, 2632, 0), +(34089, 0, 45952, 0, 0, 2632, 0), +(34089, 0, 45953, 0, 0, 2632, 0), +(34089, 0, 45954, 0, 0, 2632, 0), +(34089, 0, 45955, 0, 0, 2632, 0), +(34089, 0, 45956, 0, 0, 2632, 0), +(34089, 0, 45957, 0, 0, 2634, 0), +(34089, 0, 45958, 0, 0, 2634, 0), +(34089, 0, 45959, 0, 0, 2634, 0), +(34089, 0, 45960, 0, 0, 2634, 0), +(34089, 0, 45961, 0, 0, 2635, 0), +(34089, 0, 45962, 0, 0, 2635, 0), +(34089, 0, 45963, 0, 0, 2635, 0), +(34089, 0, 45964, 0, 0, 2635, 0), +(34089, 0, 45965, 0, 0, 2635, 0), +(34089, 0, 45966, 0, 0, 2635, 0), +(34089, 0, 45967, 0, 0, 2635, 0), +(34089, 0, 45968, 0, 0, 2635, 0), +(34089, 0, 45969, 0, 0, 2634, 0), +(34089, 0, 45970, 0, 0, 2633, 0), +(34089, 0, 45971, 0, 0, 2633, 0); diff --git a/data/sql/updates/db_world/2026_04_27_00.sql b/data/sql/updates/db_world/2026_04_27_00.sql new file mode 100644 index 000000000..79bf3a10f --- /dev/null +++ b/data/sql/updates/db_world/2026_04_27_00.sql @@ -0,0 +1,4 @@ +-- DB update 2026_04_26_05 -> 2026_04_27_00 + +-- Change target to self. +UPDATE `smart_scripts` SET `target_type` = 1 WHERE (`entryorguid` = 8400) AND (`source_type` = 0) AND (`id` IN (0)); diff --git a/data/sql/updates/db_world/2026_04_28_00.sql b/data/sql/updates/db_world/2026_04_28_00.sql new file mode 100644 index 000000000..ccbf28bd3 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_00.sql @@ -0,0 +1,10 @@ +-- DB update 2026_04_27_00 -> 2026_04_28_00 +-- +DELETE FROM `gameobject_loot_template` WHERE (`Entry` = 26860); +INSERT INTO `gameobject_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(26860, 44651, 0, 100, 1, 1, 1, 1, 1, 'Heart of Magic - Heart of Magic - 25m'), +(26860, 44650, 0, 100, 1, 1, 2, 1, 1, 'Heart of Magic - Heart of Magic - 10m'); + +DELETE FROM `gameobject_questitem` WHERE (`GameObjectEntry` = 194159) AND (`Idx` IN (1)); +INSERT INTO `gameobject_questitem` (`GameObjectEntry`, `Idx`, `ItemId`, `VerifiedBuild`) VALUES +(194159, 1, 44650, 0); diff --git a/data/sql/updates/db_world/2026_04_28_01.sql b/data/sql/updates/db_world/2026_04_28_01.sql new file mode 100644 index 000000000..6eac72f17 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_01.sql @@ -0,0 +1,2 @@ +-- DB update 2026_04_28_00 -> 2026_04_28_01 +UPDATE `achievement_reward` SET `Body` = 'With the drums of war pounding in the distance, it is easy for the denizens of Azeroth to forget all that life has to offer.$B$BYou, on the other hand, have maintained the dignity of the good races of Azeroth with your ability to remember what we fight for. To not celebrate our victories is another form of defeat. Remember that well, Reveler.$B$BMay others be inspired by your good cheer,$B$BAlexstrasza the Life-Binder' WHERE `ID` IN (2144, 2145); diff --git a/data/sql/updates/db_world/2026_04_28_02.sql b/data/sql/updates/db_world/2026_04_28_02.sql new file mode 100644 index 000000000..e5cb102de --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_02.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_28_01 -> 2026_04_28_02 +-- +UPDATE `smart_scripts` SET `action_param2` = 0 WHERE `entryorguid` = 29404 AND `source_type` = 0 AND `id` = 0; diff --git a/data/sql/updates/db_world/2026_04_28_03.sql b/data/sql/updates/db_world/2026_04_28_03.sql new file mode 100644 index 000000000..96bd2869e --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_03.sql @@ -0,0 +1,343 @@ +-- DB update 2026_04_28_02 -> 2026_04_28_03 +-- Naxxramas loot pool structure fix +-- Splits single GroupId pools into multiple pools matching retail WotLK behavior +-- Source: Wowhead WotLK 25-man drop rates, WowDB cross-validation, ChromieCraft #9131 (Anub'Rekhan) + +-- ===================== +-- Spider Wing +-- ===================== + +-- Anub'Rekhan 25-man (4 pools: 5+4+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29249 AND `Item`=1 AND `Reference`=34137; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34137 AND `Item`=39701; -- Dawnwalkers +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34137 AND `Item`=39702; -- Arachnoid Gold Band +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34137 AND `Item`=39703; -- Rescinding Grips +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34137 AND `Item`=39704; -- Pauldrons of Unnatural Death +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34137 AND `Item`=39706; -- Sabatons of Sudden Reprisal + +-- Pool B (4 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34137 AND `Item`=39712; -- Gemmed Wand of the Nerubians +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34137 AND `Item`=39714; -- Webbed Death +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34137 AND `Item`=39716; -- Shield of Assimilation +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34137 AND `Item`=39717; -- Inexorable Sabatons + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34137 AND `Item`=39718; -- Corpse Scarab Handguards +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34137 AND `Item`=39719; -- Mantle of the Locusts +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34137 AND `Item`=39720; -- Leggings of Atrophy +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34137 AND `Item`=39721; -- Sash of the Parlor +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34137 AND `Item`=39722; -- Swarm Bindings + +-- Pool D (9 items, shared jewelry) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40064; -- Thunderstorm Amulet +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40065; -- Fool's Trial +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40069; -- Heritage +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40071; -- Chains of Adoration +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40074; -- Strong-Handed Ring +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40075; -- Ruthlessness +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40080; -- Lost Jewel +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40107; -- Sand-Worn Band +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34137 AND `Item`=40108; -- Seized Beauty + +-- Grand Widow Faerlina 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29268 AND `Item`=1 AND `Reference`=34138; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34138 AND `Item`=39723; -- Fire-Scorched Greathelm +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34138 AND `Item`=39724; -- Cult's Chestguard +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34138 AND `Item`=39725; -- Epaulets of the Grieving Servant +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34138 AND `Item`=39726; -- Callous-Hearted Gauntlets +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34138 AND `Item`=39727; -- Dislocating Handguards + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34138 AND `Item`=39728; -- Totem of Misery +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34138 AND `Item`=39729; -- Bracers of the Tyrant +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34138 AND `Item`=39730; -- Widow's Fury +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34138 AND `Item`=39731; -- Punctilious Bindings +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34138 AND `Item`=39732; -- Faerlina's Madness + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34138 AND `Item`=39733; -- Gloves of Token Respect +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34138 AND `Item`=39734; -- Atonement Greaves +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34138 AND `Item`=39735; -- Belt of False Dignity +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34138 AND `Item`=39756; -- Tunic of Prejudice +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34138 AND `Item`=39757; -- Idol of Worship + +-- Pool D (9 items, shared jewelry) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40064; -- Thunderstorm Amulet +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40065; -- Fool's Trial +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40069; -- Heritage +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40071; -- Chains of Adoration +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40074; -- Strong-Handed Ring +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40075; -- Ruthlessness +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40080; -- Lost Jewel +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40107; -- Sand-Worn Band +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34138 AND `Item`=40108; -- Seized Beauty + +-- Maexxna 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29278 AND `Item`=1 AND `Reference`=34139; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34139 AND `Item`=39758; -- The Jawbone +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34139 AND `Item`=39759; -- Ablative Chitin Girdle +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34139 AND `Item`=39760; -- Helm of Diminished Pride +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34139 AND `Item`=39761; -- Infectious Skitterer Leggings +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34139 AND `Item`=39762; -- Torn Web Wrapping + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34139 AND `Item`=39763; -- Wraith Strike +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34139 AND `Item`=39764; -- Bindings of the Hapless Prey +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34139 AND `Item`=39765; -- Sinner's Bindings +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34139 AND `Item`=39766; -- Matriarch's Spawn +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34139 AND `Item`=39767; -- Undiminished Battleplate + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34139 AND `Item`=39768; -- Cowl of the Perished +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34139 AND `Item`=40060; -- Distorted Limbs +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34139 AND `Item`=40061; -- Quivering Tunic +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34139 AND `Item`=40062; -- Digested Silken Robes +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34139 AND `Item`=40063; -- Mantle of Shattered Kinship + +-- Pool D (9 items, shared cloaks/trinkets) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40250; -- Aged Winter Cloak +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40251; -- Shroud of Luminosity +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40252; -- Cloak of the Shadowed Sun +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40253; -- Shawl of the Old Maid +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40254; -- Cloak of Averted Crisis +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40255; -- Dying Curse +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40256; -- Grim Toll +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40257; -- Defender's Code +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34139 AND `Item`=40258; -- Forethought Talisman + +-- ===================== +-- Plague Wing +-- ===================== + +-- Noth the Plaguebringer 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29615 AND `Item`=1 AND `Reference`=34147; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34147 AND `Item`=40184; -- Crippled Treads +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34147 AND `Item`=40185; -- Shoulderguards of Opportunity +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34147 AND `Item`=40186; -- Thrusting Bands +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34147 AND `Item`=40187; -- Poignant Sabatons +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34147 AND `Item`=40188; -- Gauntlets of the Disobedient + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34147 AND `Item`=40189; -- Angry Dread +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34147 AND `Item`=40190; -- Spinning Fate +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34147 AND `Item`=40191; -- Libram of Radiance +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34147 AND `Item`=40192; -- Accursed Spine +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34147 AND `Item`=40193; -- Tunic of Masked Suffering + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34147 AND `Item`=40196; -- Legguards of the Undisturbed +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34147 AND `Item`=40197; -- Gloves of the Fallen Wizard +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34147 AND `Item`=40198; -- Bands of Impurity +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34147 AND `Item`=40200; -- Belt of Potent Chanting +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34147 AND `Item`=40602; -- Robes of Mutation + +-- Pool D (9 items, shared jewelry) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40064; -- Thunderstorm Amulet +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40065; -- Fool's Trial +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40069; -- Heritage +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40071; -- Chains of Adoration +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40074; -- Strong-Handed Ring +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40075; -- Ruthlessness +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40080; -- Lost Jewel +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40107; -- Sand-Worn Band +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34147 AND `Item`=40108; -- Seized Beauty + +-- Heigan the Unclean 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29701 AND `Item`=1 AND `Reference`=34148; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34148 AND `Item`=40201; -- Leggings of Colossal Strides +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34148 AND `Item`=40203; -- Breastplate of Tormented Rage +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34148 AND `Item`=40204; -- Legguards of the Apostle +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34148 AND `Item`=40205; -- Stalk-Skin Belt +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34148 AND `Item`=40206; -- Iron-Spring Jumpers + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34148 AND `Item`=40207; -- Sigil of Awareness +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34148 AND `Item`=40208; -- Cryptfiend's Bite +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34148 AND `Item`=40209; -- Bindings of the Decrepit +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34148 AND `Item`=40210; -- Chestguard of Bitter Charms +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34148 AND `Item`=40233; -- The Undeath Carrier + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34148 AND `Item`=40234; -- Heigan's Putrid Vestments +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34148 AND `Item`=40235; -- Helm of Pilgrimage +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34148 AND `Item`=40236; -- Serene Echoes +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34148 AND `Item`=40237; -- Eruption-Scarred Boots +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34148 AND `Item`=40238; -- Gloves of the Dancing Bear + +-- Pool D (9 items, shared cloaks/trinkets) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40250; -- Aged Winter Cloak +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40251; -- Shroud of Luminosity +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40252; -- Cloak of the Shadowed Sun +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40253; -- Shawl of the Old Maid +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40254; -- Cloak of Averted Crisis +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40255; -- Dying Curse +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40256; -- Grim Toll +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40257; -- Defender's Code +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34148 AND `Item`=40258; -- Forethought Talisman + +-- ===================== +-- Military Wing +-- ===================== + +-- Instructor Razuvious 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29940 AND `Item`=1 AND `Reference`=34144; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34144 AND `Item`=40305; -- Spaulders of Egotism +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34144 AND `Item`=40306; -- Bracers of the Unholy Knight +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34144 AND `Item`=40315; -- Shoulderpads of Secret Arts +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34144 AND `Item`=40316; -- Gauntlets of Guiding Touch +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34144 AND `Item`=40317; -- Girdle of Razuvious + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34144 AND `Item`=40318; -- Legplates of Double Strikes +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34144 AND `Item`=40319; -- Chestpiece of Suspicion +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34144 AND `Item`=40320; -- Faithful Steel Sabatons +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34144 AND `Item`=40321; -- Idol of the Shooting Star +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34144 AND `Item`=40322; -- Totem of Dueling + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34144 AND `Item`=40323; -- Esteemed Bindings +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34144 AND `Item`=40324; -- Bands of Mutual Respect +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34144 AND `Item`=40325; -- Bindings of the Expansive Mind +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34144 AND `Item`=40326; -- Boots of Forlorn Wishes +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34144 AND `Item`=40327; -- Girdle of Recuperation + +-- Pool D (9 items, shared jewelry) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40064; -- Thunderstorm Amulet +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40065; -- Fool's Trial +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40069; -- Heritage +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40071; -- Chains of Adoration +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40074; -- Strong-Handed Ring +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40075; -- Ruthlessness +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40080; -- Lost Jewel +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40107; -- Sand-Worn Band +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34144 AND `Item`=40108; -- Seized Beauty + +-- Gothik the Harvester 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29955 AND `Item`=1 AND `Reference`=34145; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34145 AND `Item`=40328; -- Helm of Vital Protection +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34145 AND `Item`=40329; -- Hood of the Exodus +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34145 AND `Item`=40330; -- Bracers of Unrelenting Attack +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34145 AND `Item`=40331; -- Leggings of Failed Escape +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34145 AND `Item`=40332; -- Abetment Bracers + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34145 AND `Item`=40333; -- Leggings of Fleeting Moments +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34145 AND `Item`=40334; -- Burdened Shoulderplates +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34145 AND `Item`=40335; -- Touch of Horror +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34145 AND `Item`=40336; -- Life and Death +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34145 AND `Item`=40337; -- Libram of Resurgence + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34145 AND `Item`=40338; -- Bindings of Yearning +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34145 AND `Item`=40339; -- Gothik's Cowl +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34145 AND `Item`=40340; -- Helm of Unleashed Energy +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34145 AND `Item`=40341; -- Shackled Cinch +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34145 AND `Item`=40342; -- Idol of Awakening + +-- Pool D (9 items, shared cloaks/trinkets) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40250; -- Aged Winter Cloak +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40251; -- Shroud of Luminosity +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40252; -- Cloak of the Shadowed Sun +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40253; -- Shawl of the Old Maid +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40254; -- Cloak of Averted Crisis +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40255; -- Dying Curse +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40256; -- Grim Toll +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40257; -- Defender's Code +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34145 AND `Item`=40258; -- Forethought Talisman + +-- ===================== +-- Construct Wing +-- ===================== + +-- Patchwerk 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29324 AND `Item`=1 AND `Reference`=34140; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34140 AND `Item`=40259; -- Waistguard of Divine Grace +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34140 AND `Item`=40260; -- Belt of the Tortured +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34140 AND `Item`=40261; -- Crude Discolored Battlegrips +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34140 AND `Item`=40262; -- Gloves of Calculated Risk +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34140 AND `Item`=40263; -- Fleshless Girdle + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34140 AND `Item`=40264; -- Split Greathammer +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34140 AND `Item`=40265; -- Arrowsong +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34140 AND `Item`=40266; -- Hero's Surrender +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34140 AND `Item`=40267; -- Totem of Hex +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34140 AND `Item`=40268; -- Libram of Tolerance + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34140 AND `Item`=40269; -- Boots of Persuasion +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34140 AND `Item`=40270; -- Boots of Septic Wounds +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34140 AND `Item`=40271; -- Sash of Solitude +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34140 AND `Item`=40272; -- Girdle of the Gambit +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34140 AND `Item`=40273; -- Surplus Limb + +-- Pool D (9 items, shared jewelry) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40064; -- Thunderstorm Amulet +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40065; -- Fool's Trial +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40069; -- Heritage +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40071; -- Chains of Adoration +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40074; -- Strong-Handed Ring +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40075; -- Ruthlessness +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40080; -- Lost Jewel +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40107; -- Sand-Worn Band +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34140 AND `Item`=40108; -- Seized Beauty + +-- Grobbulus 25-man (4 pools: 5+5+5+9) +UPDATE `creature_loot_template` SET `MinCount`=1, `MaxCount`=1 + WHERE `Entry`=29373 AND `Item`=1 AND `Reference`=34141; + +-- Pool A (5 items) +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34141 AND `Item`=40274; -- Bracers of Liberation +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34141 AND `Item`=40275; -- Depraved Linked Belt +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34141 AND `Item`=40277; -- Tunic of Indulgence +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34141 AND `Item`=40278; -- Girdle of Chivalry +UPDATE `reference_loot_template` SET `GroupId`=1 WHERE `Entry`=34141 AND `Item`=40279; -- Chestguard of the Exhausted + +-- Pool B (5 items) +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34141 AND `Item`=40280; -- Origin of Nightmares +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34141 AND `Item`=40281; -- Twilight Mist +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34141 AND `Item`=40282; -- Slime Stream Bands +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34141 AND `Item`=40283; -- Fallout Impervious Tunic +UPDATE `reference_loot_template` SET `GroupId`=2 WHERE `Entry`=34141 AND `Item`=40284; -- Plague Igniter + +-- Pool C (5 items) +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34141 AND `Item`=40285; -- Desecrated Past +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34141 AND `Item`=40287; -- Cowl of Vanity +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34141 AND `Item`=40288; -- Spaulders of Incoherence +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34141 AND `Item`=40289; -- Sympathetic Amice +UPDATE `reference_loot_template` SET `GroupId`=3 WHERE `Entry`=34141 AND `Item`=40351; -- Mantle of the Fatigued Sage + +-- Pool D (9 items, shared cloaks/trinkets) +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40250; -- Aged Winter Cloak +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40251; -- Shroud of Luminosity +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40252; -- Cloak of the Shadowed Sun +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40253; -- Shawl of the Old Maid +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40254; -- Cloak of Averted Crisis +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40255; -- Dying Curse +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40256; -- Grim Toll +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40257; -- Defender's Code +UPDATE `reference_loot_template` SET `GroupId`=4 WHERE `Entry`=34141 AND `Item`=40258; -- Forethought Talisman diff --git a/data/sql/updates/db_world/2026_04_28_04.sql b/data/sql/updates/db_world/2026_04_28_04.sql new file mode 100644 index 000000000..cbbf43d82 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_04.sql @@ -0,0 +1,15 @@ +-- DB update 2026_04_28_03 -> 2026_04_28_04 +-- Adds S6 off piece vendors to creature table, and then adds them to S6 event. +DELETE FROM `creature` WHERE (`guid` IN (208509, 208510, 208511, 208512) AND `id1` IN (34036, 34058, 34073, 34076)); +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`, `CreateObject`, `Comment`) VALUES +(208509, 34036, 0, 0, 1, 0, 0, 1, 1, 1, 1669.09, -4196.78, 56.3827, 4.10416, 25, 0, 0, 11828, 0, 0, 0, 0, 0, '', 0, 0, NULL), +(208510, 34058, 0, 0, 1, 0, 0, 1, 1, 0, 1673.07, -4201.89, 56.3826, 3.62927, 25, 0, 0, 55888, 0, 0, 0, 0, 0, '', 0, 0, NULL), +(208511, 34073, 0, 0, 0, 0, 0, 1, 1, 1, -8781.18, 419.883, 105.233, 6.18459, 180, 0, 0, 7048, 0, 0, 0, 0, 0, '', 0, 0, NULL), +(208512, 34076, 0, 0, 0, 0, 0, 1, 1, 1, -8773.78, 425.804, 105.233, 4.80621, 180, 0, 0, 11828, 0, 0, 0, 0, 0, '', 0, 0, NULL); + +DELETE FROM `game_event_creature` WHERE (`guid` IN (208509, 208510, 208511, 208512) AND `eventEntry` = 58); +INSERT INTO `game_event_creature` (`guid`, `eventEntry`) VALUES +(208509, 58), +(208510, 58), +(208511, 58), +(208512, 58); diff --git a/data/sql/updates/db_world/2026_04_28_05.sql b/data/sql/updates/db_world/2026_04_28_05.sql new file mode 100644 index 000000000..0eee825b7 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_05.sql @@ -0,0 +1,4 @@ +-- DB update 2026_04_28_04 -> 2026_04_28_05 +-- Ribbon of Sacrifice (28590) - Blessing of Life proc on direct heals +DELETE FROM `spell_proc` WHERE `SpellId` = 38332; +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES (38332, 0, 0, 0, 0, 0, 0x4000, 2, 2, 0, 0, 0, 0, 100, 0, 0); diff --git a/data/sql/updates/db_world/2026_04_28_06.sql b/data/sql/updates/db_world/2026_04_28_06.sql new file mode 100644 index 000000000..88b4e4959 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_28_06.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_28_05 -> 2026_04_28_06 +-- Fix Spark of Life (spell 60519) proc on craft and equip +UPDATE `spell_proc` SET `SpellTypeMask` = 3 WHERE `SpellId` = 60519; diff --git a/data/sql/updates/db_world/2026_04_29_00.sql b/data/sql/updates/db_world/2026_04_29_00.sql new file mode 100644 index 000000000..f116c5564 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_00.sql @@ -0,0 +1,3 @@ +-- DB update 2026_04_28_06 -> 2026_04_29_00 +DELETE FROM `smart_scripts` WHERE `entryorguid`=28615 AND `source_type`=0 AND `id` IN (0,1); +UPDATE `creature_template` SET `AIName`='' WHERE `entry`=28615; diff --git a/data/sql/updates/db_world/2026_04_29_01.sql b/data/sql/updates/db_world/2026_04_29_01.sql new file mode 100644 index 000000000..46a6490ba --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_01.sql @@ -0,0 +1,13 @@ +-- DB update 2026_04_29_00 -> 2026_04_29_01 + +-- Add CastFlags 32 and update comments. +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 30202; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 30202); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(30202, 0, 0, 1, 8, 0, 100, 1, 57806, 0, 0, 0, 0, 0, 11, 57808, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - On Spellhit \'Sprinkle Holy Water\' - Cast \'Freed Crusader Soul\' (No Repeat)'), +(30202, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - On Spellhit \'Sprinkle Holy Water\' - Despawn Instant (No Repeat)'), +(30202, 0, 2, 0, 0, 0, 100, 0, 1000, 5000, 6500, 12000, 0, 0, 11, 32674, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - In Combat - Cast \'Avenger`s Shield\''), +(30202, 0, 3, 0, 0, 0, 100, 0, 7000, 12000, 8500, 20000, 0, 0, 11, 58154, 32, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - In Combat - Cast \'Hammer of Injustice\''), +(30202, 0, 4, 0, 2, 0, 100, 0, 10, 90, 7000, 15000, 0, 0, 11, 58153, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - Between 10-90% Health - Cast \'Unholy Light\''), +(30202, 0, 5, 0, 14, 0, 100, 0, 1000, 20, 8000, 20000, 0, 0, 11, 58153, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Crusader - Friendly At 1000 Health - Cast \'Unholy Light\''); diff --git a/data/sql/updates/db_world/2026_04_29_02.sql b/data/sql/updates/db_world/2026_04_29_02.sql new file mode 100644 index 000000000..5a503eb6a --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_02.sql @@ -0,0 +1,21 @@ +-- DB update 2026_04_29_01 -> 2026_04_29_02 +-- +-- Quest 12943 "Shadow Vault Decree" - Thane Ufrang the Mighty (29919) +-- +-- The CheckCast "Thane is nearby" check moves out of spell_q12943_shadow_vault_decree +-- and into a CONDITION_NEAR_CREATURE on spell 31696. The script now also clears +-- Thane's idle unit flags via ReplaceAllUnitFlags before calling AttackStart, so +-- combat actually engages instead of the player getting stuck unable to attack. +-- +-- The old SAI "Remove Unit Flags" action (id 6) chained off the 12s "Say Line 4" +-- timer is removed - the C++ handles flag removal at cast time. +-- + +-- Cast-time precondition: Thane (alive) must be within 30y of the caster. +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 17 AND `SourceEntry` = 31696; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 31696, 0, 0, 29, 0, 29919, 30, 0, 0, 12, 0, '', 'Spell Shadow Vault Decree requires nearby Thane Ufrang the Mighty'); + +-- Drop the now-redundant linked Remove-Unit-Flags action and its parent's link to it. +UPDATE `smart_scripts` SET `link` = 0 WHERE `entryorguid` = 29919 AND `source_type` = 0 AND `id` = 5; +DELETE FROM `smart_scripts` WHERE `entryorguid` = 29919 AND `source_type` = 0 AND `id` = 6; diff --git a/data/sql/updates/db_world/2026_04_29_03.sql b/data/sql/updates/db_world/2026_04_29_03.sql new file mode 100644 index 000000000..b8e5263fa --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_03.sql @@ -0,0 +1,8 @@ +-- DB update 2026_04_29_02 -> 2026_04_29_03 +-- Allow Eye of Dominion (Rise of Suffering, GO 193424 / gossip menu 10111) to +-- show its "Seize control of a Lithe Stalker" gossip option for quest 13160 +-- (Stunning View). Without this row players who have only Stunning View active +-- see no gossip option and cannot progress the quest. +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 10111) AND (`SourceEntry` = 0) AND (`SourceId` = 0) AND (`ElseGroup` = 3) AND (`ConditionTypeOrReference` = 9) AND (`ConditionValue1` = 13160); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 10111, 0, 0, 3, 9, 0, 13160, 0, 0, 0, 0, 0, '', 'Show Gossip option only if player has quest Stunning View active'); diff --git a/data/sql/updates/db_world/2026_04_29_04.sql b/data/sql/updates/db_world/2026_04_29_04.sql new file mode 100644 index 000000000..751083abb --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_04.sql @@ -0,0 +1,7 @@ +-- DB update 2026_04_29_03 -> 2026_04_29_04 +-- +-- Unit flags observed: 8, 2304 (256 | 2048) +-- +256 IMMUNE_TO_PC - disables combat/assistance with PlayerCharacters (PC) +-- +2048 PET_IN_COMBAT +UPDATE `creature_template` SET `faction` = 2101, `unit_flags` = 256, `unit_flags2` = 2048 WHERE (`entry` IN (32343, 32342, 32324, 32321)); +UPDATE `creature_template` SET `faction` = 1770, `unit_flags` = 256, `unit_flags2` = 2048 WHERE (`entry` IN (32322, 32341, 32340, 32325)); diff --git a/data/sql/updates/db_world/2026_04_29_05.sql b/data/sql/updates/db_world/2026_04_29_05.sql new file mode 100644 index 000000000..12008d9c0 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_05.sql @@ -0,0 +1,13 @@ +-- DB update 2026_04_29_04 -> 2026_04_29_05 +-- +-- Sartharion 25M drops 2x T7.5 Gloves +SET @REF := 34377; +DELETE FROM `creature_loot_template` WHERE (`Entry` = 31311) AND (`Item` IN (5, 40628, 40629, 40630)); +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(31311, 5, -@REF, 100, 0, 1, 0, 2, 2, 'Sartharion (1) - (ReferenceTable)'); + +DELETE FROM `reference_loot_template` WHERE (`Entry` = @REF) AND (`Item` IN (40752, 40628, 40629, 40630)); +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(@REF, 40628, 0, 0, 0, 1, 1, 1, 1, 'T7.5 Gloves Token'), +(@REF, 40629, 0, 0, 0, 1, 1, 1, 1, 'T7.5 Gloves Token'), +(@REF, 40630, 0, 0, 0, 1, 1, 1, 1, 'T7.5 Gloves Token'); diff --git a/data/sql/updates/db_world/2026_04_29_06.sql b/data/sql/updates/db_world/2026_04_29_06.sql new file mode 100644 index 000000000..45acd6935 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_06.sql @@ -0,0 +1,4 @@ +-- DB update 2026_04_29_05 -> 2026_04_29_06 + +-- Remove DisplayID_Other_Gender. +UPDATE `creature_model_info` SET `DisplayID_Other_Gender` = 0 WHERE (`DisplayID` IN (12829, 12830)); diff --git a/data/sql/updates/db_world/2026_04_29_07.sql b/data/sql/updates/db_world/2026_04_29_07.sql new file mode 100644 index 000000000..d699d74d9 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_29_07.sql @@ -0,0 +1,25 @@ +-- DB update 2026_04_29_06 -> 2026_04_29_07 +-- +-- workaround to apply gobject scaling of 23020 Crystal Imprisonment (SPELL_AURA_MOD_SCALE), value = -90 +UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 179644; +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 179644) AND (`source_type` = 1) AND (`id` IN (0)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(179644, 1, 0, 0, 63, 0, 100, 0, 0, 0, 0, 0, 0, 0, 227, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Imprisoned Doomguard - On Just Created - Set Scale to 10%'); + +DELETE FROM `creature_text` WHERE (`CreatureID` = 14452); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(14452, 0, 0, 'A sacrifice will be due if I am ever called upon, mortal...', 12, 8, 100, 0, 0, 0, 9590, 0, ''); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `id` IN (4, 5) AND `entryorguid` = 12396); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(12396, 0, 4, 0, 8, 0, 100, 1, 23019, 0, 0, 0, 0, 0, 80, 1239600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - On Spellhit \'Crystal Prison Dummy DND\' - Run Script (No Repeat)'); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1239600) AND (`source_type` = 9); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(1239600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 36, 14452, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Update Template To \'Enslaved Doomguard Commander\''), +(1239600, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 23020, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Cast \'Crystal Imprisonment\''), +(1239600, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Set Flags Immune To Players & Immune To NPC\'s'), +(1239600, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Stop Combat'), +(1239600, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Say Line 0'), +(1239600, 9, 5, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 0, 11, 23022, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Cast \'Serverside - Crystal Prison Conjure DND\''), +(1239600, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Doomguard Commander - Actionlist - Despawn Instant'); diff --git a/data/sql/updates/db_world/2026_04_30_00.sql b/data/sql/updates/db_world/2026_04_30_00.sql new file mode 100644 index 000000000..0ece16300 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_30_00.sql @@ -0,0 +1,5 @@ +-- DB update 2026_04_29_07 -> 2026_04_30_00 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 27812 AND `ScriptName` = 'spell_kelthuzad_void_blast'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(27812, 'spell_kelthuzad_void_blast'); diff --git a/data/sql/updates/db_world/2026_04_30_01.sql b/data/sql/updates/db_world/2026_04_30_01.sql new file mode 100644 index 000000000..8f4b0602e --- /dev/null +++ b/data/sql/updates/db_world/2026_04_30_01.sql @@ -0,0 +1,39 @@ +-- DB update 2026_04_30_00 -> 2026_04_30_01 +-- +-- BRD: Hurley Blackbreath (9537) and Blackbreath Cronies (per-spawn +-- overrides -71997/-71998/-71999) start with UNIT_FLAG_UNK_6 | +-- UNIT_FLAG_IMMUNE_TO_PC (320) and only clear it via "OnReachedWP 3". +-- The encounter propagates aggro: any mob entering combat fires +-- OnAggro -> SetData 1=2 on every member, which triggers OnDataSet 1=2 +-- -> Attack on the rest. If a peer is still walking its WP path when +-- this happens, its movement is interrupted, WP 3 is never reached, +-- and the immunity flag is never cleared -> the mob stays in combat +-- but cannot be damaged or targeted. +-- +-- Failsafe: any combat-entry path also clears flag 320 on the unit. +-- Two new rows per entity: one on OnAggro, one on OnDataSet 1=2. +-- + +-- Hurley Blackbreath +DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` = 9537) AND (`id` IN (19, 20)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(9537, 0, 19, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hurley Blackbreath - On Aggro - Remove Unit Flags Immune To PC (failsafe if pulled before reaching WP 3)'), +(9537, 0, 20, 0, 38, 0, 100, 0, 1, 2, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hurley Blackbreath - On Data Set 1=2 - Remove Unit Flags Immune To PC (failsafe if pulled before reaching WP 3)'); + +-- Blackbreath Crony spawn 71997 +DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` = -71997) AND (`id` IN (14, 15)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(-71997, 0, 14, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Aggro - Remove Unit Flags Immune To PC (failsafe)'), +(-71997, 0, 15, 0, 38, 0, 100, 0, 1, 2, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Data Set 1=2 - Remove Unit Flags Immune To PC (failsafe)'); + +-- Blackbreath Crony spawn 71998 +DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` = -71998) AND (`id` IN (14, 15)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(-71998, 0, 14, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Aggro - Remove Unit Flags Immune To PC (failsafe)'), +(-71998, 0, 15, 0, 38, 0, 100, 0, 1, 2, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Data Set 1=2 - Remove Unit Flags Immune To PC (failsafe)'); + +-- Blackbreath Crony spawn 71999 +DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` = -71999) AND (`id` IN (14, 15)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(-71999, 0, 14, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Aggro - Remove Unit Flags Immune To PC (failsafe)'), +(-71999, 0, 15, 0, 38, 0, 100, 0, 1, 2, 0, 0, 0, 0, 19, 320, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Blackbreath Crony - On Data Set 1=2 - Remove Unit Flags Immune To PC (failsafe)'); diff --git a/data/sql/updates/db_world/2026_04_30_02.sql b/data/sql/updates/db_world/2026_04_30_02.sql new file mode 100644 index 000000000..fc375ee73 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_30_02.sql @@ -0,0 +1,19 @@ +-- DB update 2026_04_30_01 -> 2026_04_30_02 +-- +DELETE FROM `gameobject` WHERE (`id` = 18901) AND (`guid` IN (34006)); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES +(34006, 18901, 33, 0, 0, 1, 1, -249.22014, 2123.1018, 82.80518, 6.0923543, -0.1318922, -0.6946964, -0.1318922, 0.69469833, 0, 100, 1, '', 43400, NULL); + +DELETE FROM `gameobject` WHERE (`id` = 18900) AND (`guid` IN (32442)); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES +(32442, 18900, 33, 0, 0, 1, 1, -252.69586, 2114.2246, 82.80518, 6.0923543, -0.1318922, -0.6946964, -0.1318922, 0.69469833, 0, 100, 1, '', 43400, NULL); + +DELETE FROM `gameobject` WHERE (`id` = 101811) AND (`guid` IN (32444)); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES +(32444, 101811, 33, 0, 0, 1, 1, -245.59846, 2132.319, 82.80518, 6.0923543, -0.1318922, -0.6946964, -0.1318922, 0.69469833, 0, 100, 1, '', 43400, NULL); + +DELETE FROM `gameobject_addon` WHERE `guid` IN (32442, 34006, 32444); +INSERT INTO `gameobject_addon` (`guid`, `parent_rotation0`, `parent_rotation1`, `parent_rotation2`, `parent_rotation3`, `invisibilityType`, `invisibilityValue`) VALUES +(32442, 0, 0, -0.82658964, 0.56280506, 0, 0), +(34006, 0, 0, -0.82658964, 0.56280506, 0, 0), +(32444, 0, 0, -0.82658964, 0.56280506, 0, 0); diff --git a/data/sql/updates/db_world/2026_04_30_03.sql b/data/sql/updates/db_world/2026_04_30_03.sql new file mode 100644 index 000000000..aebce7674 --- /dev/null +++ b/data/sql/updates/db_world/2026_04_30_03.sql @@ -0,0 +1,14 @@ +-- DB update 2026_04_30_02 -> 2026_04_30_03 + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2245200); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2245200, 9, 0, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 0, 3500, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - Actionlist - Say Line 0'), +(2245200, 9, 1, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 21, 20, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - Actionlist - Set Orientation Closest Player'), +(2245200, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 0, 19, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - Actionlist - Remove Flags Immune To Players & Immune To NPC\'s'), +(2245200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 20, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - Actionlist - Start Attacking'); + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 22452; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 22452); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(22452, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 80, 2245200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - On Just Summoned - Run Script'), +(22452, 0, 1, 0, 0, 0, 100, 1, 2000, 4000, 0, 0, 0, 0, 11, 8258, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Exarch - In Combat - Cast \'Devotion Aura\' (No Repeat)'); diff --git a/data/sql/updates/db_world/2026_05_01_00.sql b/data/sql/updates/db_world/2026_05_01_00.sql new file mode 100644 index 000000000..ceab53ed7 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_01_00.sql @@ -0,0 +1,21 @@ +-- DB update 2026_04_30_03 -> 2026_05_01_00 +-- RBAC Language strings (uses {} format placeholders for Acore::StringFormat) +DELETE FROM `acore_string` WHERE `entry` BETWEEN 63 AND 79; +INSERT INTO `acore_string` (`entry`, `content_default`) VALUES +(63, 'Wrong parameter id: {}, does not exist'), +(64, 'Wrong parameter realmId: {}'), +(65, 'Account {} ({}) granted permissions:'), +(66, 'Account {} ({}) denied permissions:'), +(67, 'Account {} ({}) inherited permissions by sec level {} ({}):'), +(68, 'Permissions:'), +(69, 'Linked permissions:'), +(70, 'Empty List'), +(71, '- {} ({})'), +(72, 'Could not grant permission {} ({}) realmId {}. Account {} ({}) already has that permission'), +(73, 'Could not grant permission {} ({}) realmId {}. Account {} ({}) has that permission in deny list'), +(74, 'Granted permission {} ({}) realmId {} to account {} ({})'), +(75, 'Could not deny permission {} ({}) realmId {}. Account {} ({}) already has that permission'), +(76, 'Could not deny permission {} ({}) realmId {}. Account {} ({}) has that permission in grant list'), +(77, 'Denied permission {} ({}) realmId {} to account {} ({})'), +(78, 'Revoked permission {} ({}) realmId {} to account {} ({})'), +(79, 'Could not revoke permission {} ({}) realmId {}. Account {} ({}) does not have that permission'); diff --git a/data/sql/updates/db_world/2026_05_01_01.sql b/data/sql/updates/db_world/2026_05_01_01.sql new file mode 100644 index 000000000..52d8e428d --- /dev/null +++ b/data/sql/updates/db_world/2026_05_01_01.sql @@ -0,0 +1,13 @@ +-- DB update 2026_05_01_00 -> 2026_05_01_01 +-- RBAC command help strings +DELETE FROM `acore_string` WHERE `entry` BETWEEN 83 AND 86; +INSERT INTO `acore_string` (`entry`, `content_default`) VALUES +(83, 'Syntax: .rbac account list $account\nList granted, denied, and inherited permissions for the account.'), +(84, 'Syntax: .rbac account grant $account $permissionId [$realmId]\nGrant a permission to the account. Optional realmId (-1 = all realms).'), +(85, 'Syntax: .rbac account deny $account $permissionId [$realmId]\nDeny a permission for the account. Optional realmId (-1 = all realms).'), +(86, 'Syntax: .rbac account revoke $account $permissionId [$realmId]\nRevoke a previously granted or denied permission. Optional realmId (-1 = all realms).'); + +-- Update inherited permissions header to include sec level name +DELETE FROM `acore_string` WHERE `entry` = 67; +INSERT INTO `acore_string` (`entry`, `content_default`) VALUES +(67, 'Account {} ({}) inherited permissions by sec level {} ({}):'); diff --git a/data/sql/updates/db_world/2026_05_01_02.sql b/data/sql/updates/db_world/2026_05_01_02.sql new file mode 100644 index 000000000..c8e05a356 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_01_02.sql @@ -0,0 +1,10 @@ +-- DB update 2026_05_01_01 -> 2026_05_01_02 + +-- Set Aura for Scarlet Inquisitor (corpse) +UPDATE `creature_template_addon` SET `auras` = '29266 52951' WHERE `entry` = 29029; + +-- Set Aura for Death Knights and Dummy +UPDATE `creature_template_addon` SET `auras` = '52951' WHERE `entry` IN (29030, 29031, 29038); + +-- Set Aura for Plaguefist and Prisoners +UPDATE `creature_addon` SET `auras` = '52951' WHERE (`guid` IN (129947, 129905, 129950, 129955, 129959, 129961, 129964, 129965, 129966, 129967, 129968)); diff --git a/data/sql/updates/db_world/2026_05_01_03.sql b/data/sql/updates/db_world/2026_05_01_03.sql new file mode 100644 index 000000000..6ca527460 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_01_03.sql @@ -0,0 +1,6 @@ +-- DB update 2026_05_01_02 -> 2026_05_01_03 +-- +-- Add an explicit CallForHelp action with a 60-yard radius because CallForAssistance's default 10-yard range is too small. +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 16573) AND (`source_type` = 0) AND (`id` = 6); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(16573, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crypt Guard - On Aggro - Call For Help'); diff --git a/data/sql/updates/db_world/2026_05_01_04.sql b/data/sql/updates/db_world/2026_05_01_04.sql new file mode 100644 index 000000000..4bc2e532e --- /dev/null +++ b/data/sql/updates/db_world/2026_05_01_04.sql @@ -0,0 +1,28 @@ +-- DB update 2026_05_01_03 -> 2026_05_01_04 + +-- Set Quest Pre-requisite From the Depths of Azjol-Nerub for Strength of Icemist. +UPDATE `quest_template_addon` SET `PrevQuestID` = 12036 WHERE (`ID` = 12063); + +-- Delete wrong guid (Taunka Soldier) +DELETE FROM `creature` WHERE (`id1` = 26437) AND (`guid` IN (102363)); +DELETE FROM `creature_addon` WHERE (`guid` IN (102363)); + +-- Set Reward Spells +UPDATE `quest_template` SET `RewardSpell` = 46997 WHERE `ID` = 11978; +UPDATE `quest_template` SET `RewardSpell` = 47418 WHERE `ID` = 12069; + +DELETE FROM `spell_area` WHERE (`spell` IN (46997, 47418)); +INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES +(46997, 4165, 11978, 0, 0, 0, 2, 1, 64, 0), +(47418, 4165, 12069, 0, 0, 0, 2, 1, 64, 0); + +-- Set Auras (Taunka Soldiers & Greatmother Icemist) +UPDATE `creature_addon` SET `auras` = '46996' WHERE (`guid` IN (102326, 102327, 102328, 102329, 102330, 102331, 102332, 102333, 102337, 102338, 102340, 102341, 98402)); + +-- Set Unit Flags for Roanauk Icemist (Sniffed) +UPDATE `creature_template` SET `unit_flags` = `unit_flags` |768 WHERE (`entry` = 26810); + +-- Set Auras (Roanauk Icemist) +DELETE FROM `creature_template_addon` WHERE (`entry` = 26810); +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES +(26810, 0, 0, 0, 0, 0, 0, '47417'); diff --git a/data/sql/updates/db_world/2026_05_02_00.sql b/data/sql/updates/db_world/2026_05_02_00.sql new file mode 100644 index 000000000..23e25301b --- /dev/null +++ b/data/sql/updates/db_world/2026_05_02_00.sql @@ -0,0 +1,5 @@ +-- DB update 2026_05_01_04 -> 2026_05_02_00 +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28006 AND `id` = 7); + +UPDATE `vehicle_template_accessory` SET `summontype` = 1, `summontimer` = 30000 + WHERE `entry` = 28018 AND `accessory_entry` = 28006; diff --git a/data/sql/updates/db_world/2026_05_02_01.sql b/data/sql/updates/db_world/2026_05_02_01.sql new file mode 100644 index 000000000..02dc3dd4f --- /dev/null +++ b/data/sql/updates/db_world/2026_05_02_01.sql @@ -0,0 +1,4 @@ +-- DB update 2026_05_02_00 -> 2026_05_02_01 + +-- Update Quest Requirement +UPDATE `item_loot_template` SET `QuestRequired` = 0 WHERE (`Entry` = 11107) AND (`Item` IN (11108)); diff --git a/data/sql/updates/db_world/2026_05_02_02.sql b/data/sql/updates/db_world/2026_05_02_02.sql new file mode 100644 index 000000000..d3341137d --- /dev/null +++ b/data/sql/updates/db_world/2026_05_02_02.sql @@ -0,0 +1,12 @@ +-- DB update 2026_05_02_01 -> 2026_05_02_02 + +-- Set Probability to 0 for Mine Car and Iron Dwarf Relic second model. +UPDATE `creature_template_model` SET `Probability` = 0 WHERE (`CreatureID` IN (28817, 24824)) AND (`Idx` IN (1)); + +-- Edit Mine Car SAI (Row 0 Removed). +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28817; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28817); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28817, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 12, 28841, 8, 0, 0, 0, 0, 8, 0, 0, 0, 0, 2382.17, -5899.67, 107.745, 0, 'Mine Car - On Just Summoned - Summon Creature \'Scarlet Miner\''), +(28817, 0, 1, 0, 8, 0, 100, 0, 52465, 0, 0, 0, 0, 0, 29, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Mine Car - On Spellhit \'Drag Mine Cart\' - Start Follow Invoker'); diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index fc28f7d0f..a82d08026 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -154,6 +154,14 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_ACCOUNT_TOTP_SECRET, "UPDATE account SET totp_secret = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_UPTIME, "INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES (?, ?, 0, ?)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH); + + // RBAC + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_BOTH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_RBAC_DEFAULT_PERMISSIONS, "SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = ? OR realmId = -1) ORDER BY secId ASC", CONNECTION_SYNCH); } LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 5d99e7ce8..8dde435f7 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -134,6 +134,14 @@ enum LoginDatabaseStatements : uint32 LOGIN_INS_UPTIME, + LOGIN_GET_EMAIL_BY_ID, + + // RBAC + LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, + LOGIN_INS_RBAC_ACCOUNT_PERMISSION, + LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, + LOGIN_SEL_RBAC_DEFAULT_PERMISSIONS, + MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index c80e2a0ac..8ce3641e8 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -818,6 +818,10 @@ bool SmartAI::AssistPlayerInCombatAgainst(Unit* who) if (!me->IsValidAssistTarget(who->GetVictim())) return false; + // Do not engage if we cannot actually attack the attacker (e.g. neutral faction) + if (!me->IsValidAttackTarget(who)) + return false; + //too far away and no free sight? if (me->IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who)) { diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index fcd03bd24..81bfa0c04 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3082,9 +3082,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (WorldObject* target : targets) { if (IsUnit(target)) - { target->ToUnit()->SetObjectScale(scale); - } + else if (IsGameObject(target)) + target->ToGameObject()->SetObjectScale(scale); } break; } diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 8be9d5168..83e689fa9 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -1,10 +1,10 @@ /* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -18,315 +18,525 @@ #include "AccountMgr.h" #include "Common.h" #include "DatabaseEnv.h" +#include "Log.h" #include "ObjectAccessor.h" #include "Player.h" +#include "Realm.h" #include "SRP6.h" #include "ScriptMgr.h" #include "Util.h" #include "WorldSession.h" -namespace AccountMgr +AccountMgr::AccountMgr() { } + +AccountMgr::~AccountMgr() { + ClearRBAC(); +} - AccountOpResult CreateAccount(std::string username, std::string password, std::string email /*= ""*/) +AccountMgr* AccountMgr::instance() +{ + static AccountMgr instance; + return &instance; +} + +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) +{ + if (utf8length(username) > MAX_ACCOUNT_STR) + return AOR_NAME_TOO_LONG; // username's too long + + if (utf8length(password) > MAX_PASS_STR) + return AOR_PASS_TOO_LONG; // password's too long + + if (utf8length(email) > MAX_EMAIL_STR) + return AOR_EMAIL_TOO_LONG; // email is too long + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); + + if (GetId(username)) + return AOR_NAME_ALREADY_EXIST; // username does already exist + + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); + + stmt->SetData(0, username); + auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(username, password); + stmt->SetData(1, salt); + stmt->SetData(2, verifier); + stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION))); + stmt->SetData(4, email); + stmt->SetData(5, email); + + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); + + LoginDatabase.Execute(stmt); + + return AOR_OK; // everything's fine +} + +AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) +{ + std::string username; + + if (!GetName(accountId, username)) { - if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long - - if (utf8length(password) > MAX_PASS_STR) - return AOR_PASS_TOO_LONG; // password's too long - - if (utf8length(email) > MAX_EMAIL_STR) - return AOR_EMAIL_TOO_LONG; // email is too long - - Utf8ToUpperOnlyLatin(username); - Utf8ToUpperOnlyLatin(password); - Utf8ToUpperOnlyLatin(email); - - if (GetId(username)) - return AOR_NAME_ALREADY_EXIST; // username does already exist - - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); - - stmt->SetData(0, username); - auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(username, password); - stmt->SetData(1, salt); - stmt->SetData(2, verifier); - stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION))); - stmt->SetData(4, email); - stmt->SetData(5, email); - - LoginDatabase.Execute(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); - - LoginDatabase.Execute(stmt); - - return AOR_OK; // everything's fine + sScriptMgr->OnFailedEmailChange(accountId); + return AOR_NAME_NOT_EXIST; // account doesn't exist } - AccountOpResult ChangeEmail(uint32 accountId, std::string newEmail) + if (utf8length(newEmail) > MAX_EMAIL_STR) { - std::string username; - - if (!GetName(accountId, username)) - { - sScriptMgr->OnFailedEmailChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist - } - - if (utf8length(newEmail) > MAX_EMAIL_STR) - { - sScriptMgr->OnFailedEmailChange(accountId); - return AOR_EMAIL_TOO_LONG; // email's too long - } - - Utf8ToUpperOnlyLatin(newEmail); - - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); - stmt->SetData(0, newEmail); - stmt->SetData(1, accountId); - LoginDatabase.Execute(stmt); - - sScriptMgr->OnEmailChange(accountId); - return AOR_OK; + sScriptMgr->OnFailedEmailChange(accountId); + return AOR_EMAIL_TOO_LONG; // email's too long } - AccountOpResult DeleteAccount(uint32 accountId) + Utf8ToUpperOnlyLatin(newEmail); + + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); + stmt->SetData(0, newEmail); + stmt->SetData(1, accountId); + LoginDatabase.Execute(stmt); + + sScriptMgr->OnEmailChange(accountId); + return AOR_OK; +} + +AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) +{ + // Check if accounts exists + LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); + loginStmt->SetData(0, accountId); + + PreparedQueryResult result = LoginDatabase.Query(loginStmt); + if (!result) + return AOR_NAME_NOT_EXIST; + + sScriptMgr->OnBeforeAccountDelete(accountId); + + // Obtain accounts characters + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); + stmt->SetData(0, accountId); + + result = CharacterDatabase.Query(stmt); + + if (result) { - // Check if accounts exists - LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); - loginStmt->SetData(0, accountId); - - PreparedQueryResult result = LoginDatabase.Query(loginStmt); - if (!result) - return AOR_NAME_NOT_EXIST; - - sScriptMgr->OnBeforeAccountDelete(accountId); - - // Obtain accounts characters - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); - stmt->SetData(0, accountId); - - result = CharacterDatabase.Query(stmt); - - if (result) + do { - do + ObjectGuid guid = ObjectGuid::Create((*result)[0].Get()); + + // Kick if player is online + if (Player* p = ObjectAccessor::FindPlayer(guid)) { - ObjectGuid guid = ObjectGuid::Create((*result)[0].Get()); + WorldSession* s = p->GetSession(); + s->KickPlayer("Delete account"); // mark session to remove at next session list update + s->LogoutPlayer(false); // logout player without waiting next session list update + } - // Kick if player is online - if (Player* p = ObjectAccessor::FindPlayer(guid)) - { - WorldSession* s = p->GetSession(); - s->KickPlayer("Delete account"); // mark session to remove at next session list update - s->LogoutPlayer(false); // logout player without waiting next session list update - } - - Player::DeleteFromDB(guid.GetCounter(), accountId, false, true); // no need to update realm characters - } while (result->NextRow()); - } - - // table realm specific but common for all characters of account for realm - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS); - stmt->SetData(0, accountId); - CharacterDatabase.Execute(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA); - stmt->SetData(0, accountId); - CharacterDatabase.Execute(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN); - stmt->SetData(0, accountId); - CharacterDatabase.Execute(stmt); - - LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); - - loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT); - loginStmt->SetData(0, accountId); - trans->Append(loginStmt); - - loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); - loginStmt->SetData(0, accountId); - trans->Append(loginStmt); - - loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS); - loginStmt->SetData(0, accountId); - trans->Append(loginStmt); - - loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED); - loginStmt->SetData(0, accountId); - trans->Append(loginStmt); - - loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_MUTED); - loginStmt->SetData(0, accountId); - trans->Append(loginStmt); - - LoginDatabase.CommitTransaction(trans); - - return AOR_OK; + Player::DeleteFromDB(guid.GetCounter(), accountId, false, true); // no need to update realm characters + } while (result->NextRow()); } - AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) + // table realm specific but common for all characters of account for realm + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS); + stmt->SetData(0, accountId); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA); + stmt->SetData(0, accountId); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN); + stmt->SetData(0, accountId); + CharacterDatabase.Execute(stmt); + + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); + + loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT); + loginStmt->SetData(0, accountId); + trans->Append(loginStmt); + + loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); + loginStmt->SetData(0, accountId); + trans->Append(loginStmt); + + loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS); + loginStmt->SetData(0, accountId); + trans->Append(loginStmt); + + loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED); + loginStmt->SetData(0, accountId); + trans->Append(loginStmt); + + loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_MUTED); + loginStmt->SetData(0, accountId); + trans->Append(loginStmt); + + LoginDatabase.CommitTransaction(trans); + + return AOR_OK; +} + +AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) +{ + // Check if accounts exists + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); + stmt->SetData(0, accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (!result) + return AOR_NAME_NOT_EXIST; + + if (utf8length(newUsername) > MAX_ACCOUNT_STR) + return AOR_NAME_TOO_LONG; + + if (utf8length(newPassword) > MAX_PASS_STR) + return AOR_PASS_TOO_LONG; // password's too long + + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); + stmt->SetData(0, newUsername); + stmt->SetData(1, accountId); + LoginDatabase.Execute(stmt); + + auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(newUsername, newPassword); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON); + stmt->SetData(0, salt); + stmt->SetData(1, verifier); + stmt->SetData(2, accountId); + LoginDatabase.Execute(stmt); + + return AOR_OK; +} + +AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) +{ + std::string username; + + if (!GetName(accountId, username)) { - // Check if accounts exists - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); + sScriptMgr->OnFailedPasswordChange(accountId); + return AOR_NAME_NOT_EXIST; // account doesn't exist + } + + if (utf8length(newPassword) > MAX_PASS_STR) + { + sScriptMgr->OnFailedEmailChange(accountId); + return AOR_PASS_TOO_LONG; // password's too long + } + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); + + auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(username, newPassword); + + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON); + stmt->SetData(0, salt); + stmt->SetData(1, verifier); + stmt->SetData(2, accountId); + LoginDatabase.Execute(stmt); + + sScriptMgr->OnPasswordChange(accountId); + return AOR_OK; +} + +uint32 AccountMgr::GetId(std::string const& username) +{ + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); + stmt->SetData(0, username); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + return (result) ? (*result)[0].Get() : 0; +} + +uint32 AccountMgr::GetSecurity(uint32 accountId) +{ + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); + stmt->SetData(0, accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + return (result) ? (*result)[0].Get() : uint32(SEC_PLAYER); +} + +uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) +{ + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); + stmt->SetData(0, accountId); + stmt->SetData(1, realmId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + return (result) ? (*result)[0].Get() : uint32(SEC_PLAYER); +} + +bool AccountMgr::GetName(uint32 accountId, std::string& name) +{ + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID); + stmt->SetData(0, accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (result) + { + name = (*result)[0].Get(); + return true; + } + + return false; +} + +bool AccountMgr::CheckPassword(uint32 accountId, std::string password) +{ + std::string username; + + if (!GetName(accountId, username)) + return false; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); + stmt->SetData(0, accountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + Acore::Crypto::SRP6::Salt salt = (*result)[0].Get(); + Acore::Crypto::SRP6::Verifier verifier = (*result)[1].Get(); + if (Acore::Crypto::SRP6::CheckLogin(username, password, salt, verifier)) + return true; + } + + return false; +} + +uint32 AccountMgr::GetCharactersCount(uint32 accountId) +{ + // check character count + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + stmt->SetData(0, accountId); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + return (result) ? (*result)[0].Get() : 0; +} + +bool AccountMgr::IsPlayerAccount(uint32 gmlevel) +{ + return gmlevel == SEC_PLAYER; +} + +bool AccountMgr::IsGMAccount(uint32 gmlevel) +{ + return gmlevel >= SEC_GAMEMASTER; +} + +bool AccountMgr::IsAdminAccount(uint32 gmlevel) +{ + return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE; +} + +bool AccountMgr::IsConsoleAccount(uint32 gmlevel) +{ + return gmlevel == SEC_CONSOLE; +} + +bool AccountMgr::HasPermission(uint32 accountId, uint32 permission, uint32 realmId) +{ + if (!accountId) + { + LOG_ERROR("rbac", "AccountMgr::HasPermission: Wrong accountId 0"); + return false; + } + + rbac::RBACData rbac(accountId, "", realmId, GetSecurity(accountId, realmId)); + rbac.LoadFromDB(); + bool hasPermission = rbac.HasPermission(permission); + + LOG_DEBUG("rbac", "AccountMgr::HasPermission [AccountId: {}, PermissionId: {}, realmId: {}]: {}", + accountId, permission, realmId, hasPermission); + + return hasPermission; +} + +void AccountMgr::UpdateAccountAccess(rbac::RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId) +{ + if (rbac && securityLevel != rbac->GetSecurityLevel()) + rbac->SetSecurityLevel(securityLevel); + + LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction(); + + // Delete old security level from DB + if (realmId == -1) + { + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); stmt->SetData(0, accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - if (!result) - return AOR_NAME_NOT_EXIST; - - if (utf8length(newUsername) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; - - if (utf8length(newPassword) > MAX_PASS_STR) - return AOR_PASS_TOO_LONG; // password's too long - - Utf8ToUpperOnlyLatin(newUsername); - Utf8ToUpperOnlyLatin(newPassword); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); - stmt->SetData(0, newUsername); - stmt->SetData(1, accountId); - LoginDatabase.Execute(stmt); - - auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(newUsername, newPassword); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON); - stmt->SetData(0, salt); - stmt->SetData(1, verifier); - stmt->SetData(2, accountId); - LoginDatabase.Execute(stmt); - - return AOR_OK; + trans->Append(stmt); } - - AccountOpResult ChangePassword(uint32 accountId, std::string newPassword) + else { - std::string username; - - if (!GetName(accountId, username)) - { - sScriptMgr->OnFailedPasswordChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist - } - - if (utf8length(newPassword) > MAX_PASS_STR) - { - sScriptMgr->OnFailedEmailChange(accountId); - return AOR_PASS_TOO_LONG; // password's too long - } - - Utf8ToUpperOnlyLatin(username); - Utf8ToUpperOnlyLatin(newPassword); - - auto [salt, verifier] = Acore::Crypto::SRP6::MakeRegistrationData(username, newPassword); - - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON); - stmt->SetData(0, salt); - stmt->SetData(1, verifier); - stmt->SetData(2, accountId); - LoginDatabase.Execute(stmt); - - sScriptMgr->OnPasswordChange(accountId); - return AOR_OK; - } - - uint32 GetId(std::string const& username) - { - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); - stmt->SetData(0, username); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - return (result) ? (*result)[0].Get() : 0; - } - - uint32 GetSecurity(uint32 accountId) - { - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); - stmt->SetData(0, accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - return (result) ? (*result)[0].Get() : uint32(SEC_PLAYER); - } - - uint32 GetSecurity(uint32 accountId, int32 realmId) - { - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); stmt->SetData(0, accountId); stmt->SetData(1, realmId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - return (result) ? (*result)[0].Get() : uint32(SEC_PLAYER); + trans->Append(stmt); } - bool GetName(uint32 accountId, std::string& name) + // Add new security level + if (securityLevel) { - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); stmt->SetData(0, accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); + stmt->SetData(1, securityLevel); + stmt->SetData(2, realmId); + trans->Append(stmt); + } - if (result) + LoginDatabase.CommitTransaction(trans); +} + +void AccountMgr::LoadRBAC() +{ + ClearRBAC(); + + LOG_DEBUG("rbac", "AccountMgr::LoadRBAC"); + uint32 oldMSTime = getMSTime(); + uint32 count1 = 0; + uint32 count2 = 0; + uint32 count3 = 0; + + LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading permissions"); + QueryResult result = LoginDatabase.Query("SELECT id, name FROM rbac_permissions"); + if (!result) + { + LOG_INFO("server.loading", ">> Loaded 0 RBAC permissions. DB table `rbac_permissions` is empty."); + LOG_INFO("server.loading", " "); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].Get(); + _permissions[id] = new rbac::RBACPermission(id, field[1].Get()); + ++count1; + } + while (result->NextRow()); + + LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading linked permissions"); + result = LoginDatabase.Query("SELECT id, linkedId FROM rbac_linked_permissions ORDER BY id ASC"); + if (!result) + { + LOG_INFO("server.loading", ">> Loaded {} RBAC permissions", count1); + LOG_INFO("server.loading", " "); + } + else + { + uint32 permissionId = 0; + rbac::RBACPermission* permission = nullptr; + + do { - name = (*result)[0].Get(); - return true; + Field* field = result->Fetch(); + uint32 newId = field[0].Get(); + if (permissionId != newId) + { + permissionId = newId; + permission = _permissions[newId]; + } + + uint32 linkedPermissionId = field[1].Get(); + if (linkedPermissionId == permissionId) + { + LOG_ERROR("sql.sql", "RBAC Permission {} has itself as linked permission. Ignored", permissionId); + continue; + } + permission->AddLinkedPermission(linkedPermissionId); + ++count2; + } + while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} RBAC permissions and {} linked permissions in {} ms", count1, count2, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); + } + + LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions"); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_DEFAULT_PERMISSIONS); + stmt->SetData(0, int32(realm.Id.Realm)); + PreparedQueryResult defaultPermResult = LoginDatabase.Query(stmt); + if (!defaultPermResult) + { + LOG_INFO("server.loading", ">> Loaded 0 RBAC default permissions. DB table `rbac_default_permissions` is empty."); + LOG_INFO("server.loading", " "); + return; + } + + uint8 secId = 255; + rbac::RBACPermissionContainer* permissions = nullptr; + do + { + Field* field = defaultPermResult->Fetch(); + uint8 newId = field[0].Get(); + if (secId != newId || permissions == nullptr) + { + secId = newId; + permissions = &_defaultPermissions[secId]; } - return false; + permissions->insert(field[1].Get()); + ++count3; } + while (defaultPermResult->NextRow()); - bool CheckPassword(uint32 accountId, std::string password) - { - std::string username; + LOG_INFO("server.loading", ">> Loaded {} RBAC default permissions in {} ms", count3, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} - if (!GetName(accountId, username)) - return false; +rbac::RBACPermission const* AccountMgr::GetRBACPermission(uint32 permissionId) const +{ + LOG_TRACE("rbac", "AccountMgr::GetRBACPermission: {}", permissionId); + rbac::RBACPermissionsContainer::const_iterator it = _permissions.find(permissionId); + if (it != _permissions.end()) + return it->second; - Utf8ToUpperOnlyLatin(username); - Utf8ToUpperOnlyLatin(password); + return nullptr; +} - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); - stmt->SetData(0, accountId); - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - { - Acore::Crypto::SRP6::Salt salt = (*result)[0].Get(); - Acore::Crypto::SRP6::Verifier verifier = (*result)[1].Get(); - if (Acore::Crypto::SRP6::CheckLogin(username, password, salt, verifier)) - return true; - } +rbac::RBACPermissionContainer const& AccountMgr::GetRBACDefaultPermissions(uint8 secLevel) +{ + LOG_TRACE("rbac", "AccountMgr::GetRBACDefaultPermissions: secLevel {} - size: {}", secLevel, uint32(_defaultPermissions[secLevel].size())); + return _defaultPermissions[secLevel]; +} - return false; - } +void AccountMgr::ClearRBAC() +{ + for (std::pair& permission : _permissions) + delete permission.second; - uint32 GetCharactersCount(uint32 accountId) - { - // check character count - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); - stmt->SetData(0, accountId); - PreparedQueryResult result = CharacterDatabase.Query(stmt); + _permissions.clear(); + _defaultPermissions.clear(); +} - return (result) ? (*result)[0].Get() : 0; - } +void AccountMgr::AddPermissionForTest(uint32 permissionId, std::string const& name) +{ + if (_permissions.find(permissionId) != _permissions.end()) + return; - bool IsPlayerAccount(uint32 gmlevel) - { - return gmlevel == SEC_PLAYER; - } + _permissions[permissionId] = new rbac::RBACPermission(permissionId, name); +} - bool IsGMAccount(uint32 gmlevel) - { - return gmlevel >= SEC_GAMEMASTER; - } +void AccountMgr::AddLinkedPermissionForTest(uint32 permissionId, uint32 linkedPermissionId) +{ + auto it = _permissions.find(permissionId); + if (it != _permissions.end()) + it->second->AddLinkedPermission(linkedPermissionId); +} - bool IsAdminAccount(uint32 gmlevel) - { - return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE; - } +void AccountMgr::AddDefaultPermissionForTest(uint8 secLevel, uint32 permissionId) +{ + _defaultPermissions[secLevel].insert(permissionId); +} - bool IsConsoleAccount(uint32 gmlevel) - { - return gmlevel == SEC_CONSOLE; - } - -} // Namespace AccountMgr +void AccountMgr::ClearPermissionsForTest() +{ + ClearRBAC(); +} diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index c6fbbea31..d0d7ccfc9 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -1,10 +1,10 @@ /* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -18,9 +18,7 @@ #ifndef _ACCMGR_H #define _ACCMGR_H -#include "Define.h" -#include "Common.h" -#include +#include "RBAC.h" enum AccountOpResult { @@ -37,25 +35,61 @@ enum AccountOpResult #define MAX_PASS_STR 16 #define MAX_EMAIL_STR 255 -namespace AccountMgr +namespace rbac { +typedef std::map RBACPermissionsContainer; +typedef std::map RBACDefaultPermissionsContainer; +} + +class AC_GAME_API AccountMgr +{ +private: + AccountMgr(); + ~AccountMgr(); + +public: + static AccountMgr* instance(); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); - AccountOpResult DeleteAccount(uint32 accountId); - AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); - AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); - AccountOpResult ChangeEmail(uint32 accountId, std::string email); - bool CheckPassword(uint32 accountId, std::string password); + static AccountOpResult DeleteAccount(uint32 accountId); + static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); + static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); + static AccountOpResult ChangeEmail(uint32 accountId, std::string email); + static bool CheckPassword(uint32 accountId, std::string password); - uint32 GetId(std::string const& username); - uint32 GetSecurity(uint32 accountId); - uint32 GetSecurity(uint32 accountId, int32 realmId); - bool GetName(uint32 accountId, std::string& name); - uint32 GetCharactersCount(uint32 accountId); + static uint32 GetId(std::string const& username); + static uint32 GetSecurity(uint32 accountId); + static uint32 GetSecurity(uint32 accountId, int32 realmId); + static bool GetName(uint32 accountId, std::string& name); + static uint32 GetCharactersCount(uint32 accountId); - bool IsPlayerAccount(uint32 gmlevel); - bool IsGMAccount(uint32 gmlevel); - bool IsAdminAccount(uint32 gmlevel); - bool IsConsoleAccount(uint32 gmlevel); + static bool IsPlayerAccount(uint32 gmlevel); + static bool IsGMAccount(uint32 gmlevel); + static bool IsAdminAccount(uint32 gmlevel); + static bool IsConsoleAccount(uint32 gmlevel); + + static bool HasPermission(uint32 accountId, uint32 permission, uint32 realmId); + + void UpdateAccountAccess(rbac::RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId); + + void LoadRBAC(); + rbac::RBACPermission const* GetRBACPermission(uint32 permission) const; + + rbac::RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; } + rbac::RBACPermissionContainer const& GetRBACDefaultPermissions(uint8 secLevel); + + // For unit testing - allows adding permissions without database + void AddPermissionForTest(uint32 permissionId, std::string const& name); + void AddLinkedPermissionForTest(uint32 permissionId, uint32 linkedPermissionId); + void AddDefaultPermissionForTest(uint8 secLevel, uint32 permissionId); + void ClearPermissionsForTest(); + +private: + void ClearRBAC(); + rbac::RBACPermissionsContainer _permissions; + rbac::RBACDefaultPermissionsContainer _defaultPermissions; }; +#define sAccountMgr AccountMgr::instance() + #endif diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp new file mode 100644 index 000000000..99f80ef32 --- /dev/null +++ b/src/server/game/Accounts/RBAC.cpp @@ -0,0 +1,283 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "RBAC.h" +#include "AccountMgr.h" +#include "DatabaseEnv.h" +#include "Log.h" +#include "QueryResult.h" +#include + +namespace rbac +{ + +std::string GetDebugPermissionString(RBACPermissionContainer const& perms) +{ + std::string str = ""; + if (!perms.empty()) + { + std::ostringstream o; + RBACPermissionContainer::const_iterator itr = perms.begin(); + o << (*itr); + for (++itr; itr != perms.end(); ++itr) + o << ", " << uint32(*itr); + str = o.str(); + } + + return str; +} + +RBACCommandResult RBACData::GrantPermission(uint32 permissionId, int32 realmId /* = 0*/) +{ + // Check if permission Id exists + RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId); + if (!perm) + { + LOG_TRACE("rbac", "RBACData::GrantPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission does not exists", + GetId(), GetName(), permissionId, realmId); + return RBAC_ID_DOES_NOT_EXISTS; + } + + // Check if already added in denied list + if (HasDeniedPermission(permissionId)) + { + LOG_TRACE("rbac", "RBACData::GrantPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission in deny list", + GetId(), GetName(), permissionId, realmId); + return RBAC_IN_DENIED_LIST; + } + + // Already added? + if (HasGrantedPermission(permissionId)) + { + LOG_TRACE("rbac", "RBACData::GrantPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission already granted", + GetId(), GetName(), permissionId, realmId); + return RBAC_CANT_ADD_ALREADY_ADDED; + } + + AddGrantedPermission(permissionId); + + // Do not save to db when loading data from DB (realmId = 0) + if (realmId) + { + LOG_TRACE("rbac", "RBACData::GrantPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok and DB updated", + GetId(), GetName(), permissionId, realmId); + SavePermission(permissionId, true, realmId); + CalculateNewPermissions(); + } + else + LOG_TRACE("rbac", "RBACData::GrantPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok", + GetId(), GetName(), permissionId, realmId); + + return RBAC_OK; +} + +RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* = 0*/) +{ + // Check if permission Id exists + RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId); + if (!perm) + { + LOG_TRACE("rbac", "RBACData::DenyPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission does not exists", + GetId(), GetName(), permissionId, realmId); + return RBAC_ID_DOES_NOT_EXISTS; + } + + // Check if already added in granted list + if (HasGrantedPermission(permissionId)) + { + LOG_TRACE("rbac", "RBACData::DenyPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission in grant list", + GetId(), GetName(), permissionId, realmId); + return RBAC_IN_GRANTED_LIST; + } + + // Already added? + if (HasDeniedPermission(permissionId)) + { + LOG_TRACE("rbac", "RBACData::DenyPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Permission already denied", + GetId(), GetName(), permissionId, realmId); + return RBAC_CANT_ADD_ALREADY_ADDED; + } + + AddDeniedPermission(permissionId); + + // Do not save to db when loading data from DB (realmId = 0) + if (realmId) + { + LOG_TRACE("rbac", "RBACData::DenyPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok and DB updated", + GetId(), GetName(), permissionId, realmId); + SavePermission(permissionId, false, realmId); + CalculateNewPermissions(); + } + else + LOG_TRACE("rbac", "RBACData::DenyPermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok", + GetId(), GetName(), permissionId, realmId); + + return RBAC_OK; +} + +void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId) +{ + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION); + stmt->SetData(0, GetId()); + stmt->SetData(1, permission); + stmt->SetData(2, granted); + stmt->SetData(3, realmId); + LoginDatabase.Execute(stmt); +} + +RBACCommandResult RBACData::RevokePermission(uint32 permissionId, int32 realmId /* = 0*/) +{ + // Check if it's present in any list + if (!HasGrantedPermission(permissionId) && !HasDeniedPermission(permissionId)) + { + LOG_TRACE("rbac", "RBACData::RevokePermission [Id: {} Name: {}] (Permission {}, RealmId {}). Not granted or revoked", + GetId(), GetName(), permissionId, realmId); + return RBAC_CANT_REVOKE_NOT_IN_LIST; + } + + RemoveGrantedPermission(permissionId); + RemoveDeniedPermission(permissionId); + + // Do not save to db when loading data from DB (realmId = 0) + if (realmId) + { + LOG_TRACE("rbac", "RBACData::RevokePermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok and DB updated", + GetId(), GetName(), permissionId, realmId); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION); + stmt->SetData(0, GetId()); + stmt->SetData(1, permissionId); + stmt->SetData(2, realmId); + LoginDatabase.Execute(stmt); + + CalculateNewPermissions(); + } + else + LOG_TRACE("rbac", "RBACData::RevokePermission [Id: {} Name: {}] (Permission {}, RealmId {}). Ok", + GetId(), GetName(), permissionId, realmId); + + return RBAC_OK; +} + +void RBACData::LoadFromDB() +{ + ClearData(); + + LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: {} Name: {}]: Loading permissions", GetId(), GetName()); + // Load account permissions (granted and denied) that affect current realm + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); + stmt->SetData(0, GetId()); + stmt->SetData(1, GetRealmId()); + + LoadFromDBCallback(LoginDatabase.Query(stmt)); +} + +QueryCallback RBACData::LoadFromDBAsync() +{ + ClearData(); + + LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: {} Name: {}]: Loading permissions", GetId(), GetName()); + // Load account permissions (granted and denied) that affect current realm + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); + stmt->SetData(0, GetId()); + stmt->SetData(1, GetRealmId()); + + return LoginDatabase.AsyncQuery(stmt); +} + +void RBACData::LoadFromDBCallback(PreparedQueryResult result) +{ + if (result) + { + do + { + Field* fields = result->Fetch(); + if (fields[1].Get()) + GrantPermission(fields[0].Get()); + else + DenyPermission(fields[0].Get()); + } while (result->NextRow()); + } + + // Add default permissions + RBACPermissionContainer const& permissions = sAccountMgr->GetRBACDefaultPermissions(_secLevel); + for (uint32 permission : permissions) + GrantPermission(permission); + + // Force calculation of permissions + CalculateNewPermissions(); +} + +void RBACData::CalculateNewPermissions() +{ + LOG_TRACE("rbac", "RBACData::CalculateNewPermissions [Id: {} Name: {}]", GetId(), GetName()); + + // Get the list of granted permissions + _globalPerms = GetGrantedPermissions(); + ExpandPermissions(_globalPerms); + RBACPermissionContainer revoked = GetDeniedPermissions(); + ExpandPermissions(revoked); + RemovePermissions(_globalPerms, revoked); +} + +void RBACData::AddPermissions(RBACPermissionContainer const& permsFrom, RBACPermissionContainer& permsTo) +{ + for (uint32 permission : permsFrom) + permsTo.insert(permission); +} + +void RBACData::RemovePermissions(RBACPermissionContainer& permsFrom, RBACPermissionContainer const& permsToRemove) +{ + for (uint32 permission: permsToRemove) + permsFrom.erase(permission); +} + +void RBACData::ExpandPermissions(RBACPermissionContainer& permissions) +{ + RBACPermissionContainer toCheck = permissions; + permissions.clear(); + + while (!toCheck.empty()) + { + // remove the permission from original list + uint32 permissionId = *toCheck.begin(); + toCheck.erase(toCheck.begin()); + + RBACPermission const* permission = sAccountMgr->GetRBACPermission(permissionId); + if (!permission) + continue; + + // insert into the final list (expanded list) + permissions.insert(permissionId); + + // add all linked permissions (that are not already expanded) to the list of permissions to be checked + RBACPermissionContainer const& linkedPerms = permission->GetLinkedPermissions(); + for (uint32 linkedPerm : linkedPerms) + if (permissions.find(linkedPerm) == permissions.end()) + toCheck.insert(linkedPerm); + } + + LOG_DEBUG("rbac", "RBACData::ExpandPermissions: Expanded: {}", GetDebugPermissionString(permissions)); +} + +void RBACData::ClearData() +{ + _grantedPerms.clear(); + _deniedPerms.clear(); + _globalPerms.clear(); +} + +} diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h new file mode 100644 index 000000000..c4af7947e --- /dev/null +++ b/src/server/game/Accounts/RBAC.h @@ -0,0 +1,895 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/** +* @file RBAC.h +* @brief Role Based Access Control related classes definition +* +* This file contains all the classes and enums used to implement +* Role Based Access Control +* +* RBAC Rules: +* - Permission: Defines an authorization to perform certain operation. +* - Role: Set of permissions. +* - An Account can have multiple roles and permissions. +* - Account Roles and Permissions can be granted, denied or revoked +* - Grant: Assignment of the object (role/permission) and allow it +* - Deny: Assignment of the object (role/permission) and deny it +* - Revoke: Removal of the object (role/permission) no matter if it was granted or denied +* - Global Permissions are computed as: +* Role Grants + User Grants - Role Denies - User Denies +* - Roles and Permissions can be assigned by realm +*/ + +#ifndef _RBAC_H +#define _RBAC_H + +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include +#include +#include + +namespace rbac +{ + +enum RBACPermissions +{ + RBAC_PERM_INSTANT_LOGOUT = 1, + RBAC_PERM_SKIP_QUEUE = 2, + RBAC_PERM_JOIN_NORMAL_BG = 3, + RBAC_PERM_JOIN_RANDOM_BG = 4, + RBAC_PERM_JOIN_ARENAS = 5, + RBAC_PERM_JOIN_DUNGEON_FINDER = 6, + RBAC_PERM_IGNORE_IDLE_CONNECTION = 7, + RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS = 8, + RBAC_PERM_CANNOT_EARN_REALM_FIRST_ACHIEVEMENTS = 9, + // 10 not on 3.3.5a (character templates) + RBAC_PERM_LOG_GM_TRADE = 11, + // 12 not on 3.3.5a (demon hunter) + RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES = 13, + RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK = 14, + RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK = 15, + RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK = 16, + RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME = 17, + RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEATH_KNIGHT = 18, + RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ = 19, + RBAC_PERM_SKIP_CHECK_DISABLE_MAP = 20, + RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED = 21, + RBAC_PERM_SKIP_CHECK_CHAT_SPAM = 22, + RBAC_PERM_SKIP_CHECK_OVERSPEED_PING = 23, + RBAC_PERM_TWO_SIDE_CHARACTER_CREATION = 24, + RBAC_PERM_TWO_SIDE_INTERACTION_CHAT = 25, + RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL = 26, + RBAC_PERM_TWO_SIDE_INTERACTION_MAIL = 27, + RBAC_PERM_TWO_SIDE_WHO_LIST = 28, + RBAC_PERM_TWO_SIDE_ADD_FRIEND = 29, + RBAC_PERM_COMMANDS_SAVE_WITHOUT_DELAY = 30, + RBAC_PERM_COMMANDS_USE_UNSTUCK_WITH_ARGS = 31, + RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET = 32, + RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR = 33, + RBAC_PERM_COMMANDS_APPEAR_IN_GM_LIST = 34, + RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS = 35, + RBAC_PERM_CAN_FILTER_WHISPERS = 36, + RBAC_PERM_CHAT_USE_STAFF_BADGE = 37, + RBAC_PERM_RESURRECT_WITH_FULL_HPS = 38, + RBAC_PERM_RESTORE_SAVED_GM_STATE = 39, + RBAC_PERM_ALLOW_GM_FRIEND = 40, + RBAC_PERM_USE_START_GM_LEVEL = 41, + RBAC_PERM_OPCODE_WORLD_TELEPORT = 42, + RBAC_PERM_OPCODE_WHOIS = 43, + RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE = 44, + RBAC_PERM_SILENTLY_JOIN_CHANNEL = 45, + RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR = 46, + RBAC_PERM_CAN_IGNORE_LOWER_SECURITY_CHECK = 47, + RBAC_PERM_COMMANDS_PINFO_CHECK_PERSONAL_DATA = 48, + RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE = 49, + RBAC_PERM_MAY_CHECK_OWN_EMAIL = 50, + RBAC_PERM_ALLOW_TWO_SIDE_TRADE = 51, + RBAC_PERM_NO_BATTLEGROUND_DESERTER_DEBUFF = 52, + RBAC_PERM_CAN_AFK_ON_BATTLEGROUND = 53, + + // Roles (Permissions with delegated permissions) use 199 and descending + RBAC_ROLE_ADMINISTRATOR = 196, + RBAC_ROLE_GAMEMASTER = 197, + RBAC_ROLE_MODERATOR = 198, + RBAC_ROLE_PLAYER = 199, + + // Command permissions start at 200 + RBAC_PERM_COMMAND_RBAC = 200, + RBAC_PERM_COMMAND_RBAC_ACC = 201, + RBAC_PERM_COMMAND_RBAC_ACC_PERM_LIST = 202, + RBAC_PERM_COMMAND_RBAC_ACC_PERM_GRANT = 203, + RBAC_PERM_COMMAND_RBAC_ACC_PERM_DENY = 204, + RBAC_PERM_COMMAND_RBAC_ACC_PERM_REVOKE = 205, + RBAC_PERM_COMMAND_RBAC_LIST = 206, + // 207-216 not on 3.3.5a (bnet) + RBAC_PERM_COMMAND_ACCOUNT = 217, + RBAC_PERM_COMMAND_ACCOUNT_ADDON = 218, + RBAC_PERM_COMMAND_ACCOUNT_CREATE = 219, + RBAC_PERM_COMMAND_ACCOUNT_DELETE = 220, + RBAC_PERM_COMMAND_ACCOUNT_LOCK = 221, + RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY = 222, + RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP = 223, + RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST = 224, + RBAC_PERM_COMMAND_ACCOUNT_PASSWORD = 225, + RBAC_PERM_COMMAND_ACCOUNT_SET = 226, + RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON = 227, + RBAC_PERM_COMMAND_ACCOUNT_SET_SECLEVEL = 228, + RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD = 229, + RBAC_PERM_COMMAND_ACHIEVEMENT_ADD = 231, + RBAC_PERM_COMMAND_ACHIEVEMENT_CHECKALL = 232, + RBAC_PERM_COMMAND_ARENA_CAPTAIN = 233, + RBAC_PERM_COMMAND_ARENA_CREATE = 234, + RBAC_PERM_COMMAND_ARENA_DISBAND = 235, + RBAC_PERM_COMMAND_ARENA_INFO = 236, + RBAC_PERM_COMMAND_ARENA_LOOKUP = 237, + RBAC_PERM_COMMAND_ARENA_RENAME = 238, + RBAC_PERM_COMMAND_BAN_ACCOUNT = 240, + RBAC_PERM_COMMAND_BAN_CHARACTER = 241, + RBAC_PERM_COMMAND_BAN_IP = 242, + RBAC_PERM_COMMAND_BAN_PLAYERACCOUNT = 243, + RBAC_PERM_COMMAND_BANINFO_ACCOUNT = 245, + RBAC_PERM_COMMAND_BANINFO_CHARACTER = 246, + RBAC_PERM_COMMAND_BANINFO_IP = 247, + RBAC_PERM_COMMAND_BANLIST_ACCOUNT = 249, + RBAC_PERM_COMMAND_BANLIST_CHARACTER = 250, + RBAC_PERM_COMMAND_BANLIST_IP = 251, + RBAC_PERM_COMMAND_UNBAN_ACCOUNT = 253, + RBAC_PERM_COMMAND_UNBAN_CHARACTER = 254, + RBAC_PERM_COMMAND_UNBAN_IP = 255, + RBAC_PERM_COMMAND_UNBAN_PLAYERACCOUNT = 256, + RBAC_PERM_COMMAND_BF_START = 258, + RBAC_PERM_COMMAND_BF_STOP = 259, + RBAC_PERM_COMMAND_BF_SWITCH = 260, + RBAC_PERM_COMMAND_BF_TIMER = 261, + RBAC_PERM_COMMAND_BF_ENABLE = 262, + RBAC_PERM_COMMAND_ACCOUNT_EMAIL = 263, + RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL = 265, + RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_REGMAIL = 266, + RBAC_PERM_COMMAND_CAST = 267, + RBAC_PERM_COMMAND_CAST_BACK = 268, + RBAC_PERM_COMMAND_CAST_DIST = 269, + RBAC_PERM_COMMAND_CAST_SELF = 270, + RBAC_PERM_COMMAND_CAST_TARGET = 271, + RBAC_PERM_COMMAND_CAST_DEST = 272, + RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE = 274, + RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION = 275, + RBAC_PERM_COMMAND_CHARACTER_CHANGERACE = 276, + RBAC_PERM_COMMAND_CHARACTER_DELETED_DELETE = 278, + RBAC_PERM_COMMAND_CHARACTER_DELETED_LIST = 279, + RBAC_PERM_COMMAND_CHARACTER_DELETED_RESTORE = 280, + RBAC_PERM_COMMAND_CHARACTER_DELETED_OLD = 281, + RBAC_PERM_COMMAND_CHARACTER_ERASE = 282, + RBAC_PERM_COMMAND_CHARACTER_LEVEL = 283, + RBAC_PERM_COMMAND_CHARACTER_RENAME = 284, + RBAC_PERM_COMMAND_CHARACTER_REPUTATION = 285, + RBAC_PERM_COMMAND_CHARACTER_TITLES = 286, + RBAC_PERM_COMMAND_LEVELUP = 287, + RBAC_PERM_COMMAND_PDUMP_LOAD = 289, + RBAC_PERM_COMMAND_PDUMP_WRITE = 290, + RBAC_PERM_COMMAND_CHEAT_CASTTIME = 292, + RBAC_PERM_COMMAND_CHEAT_COOLDOWN = 293, + RBAC_PERM_COMMAND_CHEAT_EXPLORE = 294, + RBAC_PERM_COMMAND_CHEAT_GOD = 295, + RBAC_PERM_COMMAND_CHEAT_POWER = 296, + RBAC_PERM_COMMAND_CHEAT_STATUS = 297, + RBAC_PERM_COMMAND_CHEAT_TAXI = 298, + RBAC_PERM_COMMAND_CHEAT_WATERWALK = 299, + RBAC_PERM_COMMAND_DEBUG = 300, + // 301-342 previously used, do not reuse + RBAC_PERM_COMMAND_DESERTER_BG_ADD = 343, + RBAC_PERM_COMMAND_DESERTER_BG_REMOVE = 344, + RBAC_PERM_COMMAND_DESERTER_INSTANCE_ADD = 346, + RBAC_PERM_COMMAND_DESERTER_INSTANCE_REMOVE = 347, + RBAC_PERM_COMMAND_DISABLE_ADD_ACHIEVEMENT_CRITERIA = 350, + RBAC_PERM_COMMAND_DISABLE_ADD_BATTLEGROUND = 351, + RBAC_PERM_COMMAND_DISABLE_ADD_MAP = 352, + RBAC_PERM_COMMAND_DISABLE_ADD_MMAP = 353, + RBAC_PERM_COMMAND_DISABLE_ADD_OUTDOORPVP = 354, + RBAC_PERM_COMMAND_DISABLE_ADD_QUEST = 355, + RBAC_PERM_COMMAND_DISABLE_ADD_SPELL = 356, + RBAC_PERM_COMMAND_DISABLE_ADD_VMAP = 357, + RBAC_PERM_COMMAND_DISABLE_REMOVE_ACHIEVEMENT_CRITERIA = 359, + RBAC_PERM_COMMAND_DISABLE_REMOVE_BATTLEGROUND = 360, + RBAC_PERM_COMMAND_DISABLE_REMOVE_MAP = 361, + RBAC_PERM_COMMAND_DISABLE_REMOVE_MMAP = 362, + RBAC_PERM_COMMAND_DISABLE_REMOVE_OUTDOORPVP = 363, + RBAC_PERM_COMMAND_DISABLE_REMOVE_QUEST = 364, + RBAC_PERM_COMMAND_DISABLE_REMOVE_SPELL = 365, + RBAC_PERM_COMMAND_DISABLE_REMOVE_VMAP = 366, + RBAC_PERM_COMMAND_EVENT_INFO = 367, + RBAC_PERM_COMMAND_EVENT_ACTIVELIST = 368, + RBAC_PERM_COMMAND_EVENT_START = 369, + RBAC_PERM_COMMAND_EVENT_STOP = 370, + RBAC_PERM_COMMAND_GM = 371, + RBAC_PERM_COMMAND_GM_CHAT = 372, + RBAC_PERM_COMMAND_GM_FLY = 373, + RBAC_PERM_COMMAND_GM_INGAME = 374, + RBAC_PERM_COMMAND_GM_LIST = 375, + RBAC_PERM_COMMAND_GM_VISIBLE = 376, + RBAC_PERM_COMMAND_GO = 377, + RBAC_PERM_COMMAND_GOBJECT_ACTIVATE = 388, + RBAC_PERM_COMMAND_GOBJECT_ADD = 389, + RBAC_PERM_COMMAND_GOBJECT_ADD_TEMP = 390, + RBAC_PERM_COMMAND_GOBJECT_DELETE = 391, + RBAC_PERM_COMMAND_GOBJECT_INFO = 392, + RBAC_PERM_COMMAND_GOBJECT_MOVE = 393, + RBAC_PERM_COMMAND_GOBJECT_NEAR = 394, + RBAC_PERM_COMMAND_GOBJECT_SET_PHASE = 396, + RBAC_PERM_COMMAND_GOBJECT_SET_STATE = 397, + RBAC_PERM_COMMAND_GOBJECT_TARGET = 398, + RBAC_PERM_COMMAND_GOBJECT_TURN = 399, + RBAC_PERM_COMMAND_GUILD = 401, + RBAC_PERM_COMMAND_GUILD_CREATE = 402, + RBAC_PERM_COMMAND_GUILD_DELETE = 403, + RBAC_PERM_COMMAND_GUILD_INVITE = 404, + RBAC_PERM_COMMAND_GUILD_UNINVITE = 405, + RBAC_PERM_COMMAND_GUILD_RANK = 406, + RBAC_PERM_COMMAND_GUILD_RENAME = 407, + RBAC_PERM_COMMAND_HONOR_ADD = 409, + RBAC_PERM_COMMAND_HONOR_ADD_KILL = 410, + RBAC_PERM_COMMAND_HONOR_UPDATE = 411, + RBAC_PERM_COMMAND_INSTANCE_LISTBINDS = 413, + RBAC_PERM_COMMAND_INSTANCE_UNBIND = 414, + RBAC_PERM_COMMAND_INSTANCE_STATS = 415, + RBAC_PERM_COMMAND_INSTANCE_SAVEDATA = 416, + RBAC_PERM_COMMAND_LEARN = 417, + RBAC_PERM_COMMAND_LEARN_ALL_MY = 419, + RBAC_PERM_COMMAND_LEARN_ALL_MY_CLASS = 420, + RBAC_PERM_COMMAND_LEARN_MY_PETTALENTS = 421, + RBAC_PERM_COMMAND_LEARN_ALL_MY_SPELLS = 422, + RBAC_PERM_COMMAND_LEARN_ALL_TALENTS = 423, + RBAC_PERM_COMMAND_LEARN_ALL_GM = 424, + RBAC_PERM_COMMAND_LEARN_ALL_CRAFTS = 425, + RBAC_PERM_COMMAND_LEARN_ALL_DEFAULT = 426, + RBAC_PERM_COMMAND_LEARN_ALL_LANG = 427, + RBAC_PERM_COMMAND_LEARN_ALL_RECIPES = 428, + RBAC_PERM_COMMAND_UNLEARN = 429, + RBAC_PERM_COMMAND_LFG_PLAYER = 431, + RBAC_PERM_COMMAND_LFG_GROUP = 432, + RBAC_PERM_COMMAND_LFG_QUEUE = 433, + RBAC_PERM_COMMAND_LFG_CLEAN = 434, + RBAC_PERM_COMMAND_LFG_OPTIONS = 435, + RBAC_PERM_COMMAND_LFG_COOLDOWN = 436, + RBAC_PERM_COMMAND_LIST_CREATURE = 437, + RBAC_PERM_COMMAND_LIST_ITEM = 438, + RBAC_PERM_COMMAND_LIST_OBJECT = 439, + RBAC_PERM_COMMAND_LIST_AURAS = 440, + RBAC_PERM_COMMAND_LIST_MAIL = 441, + RBAC_PERM_COMMAND_LOOKUP = 442, + RBAC_PERM_COMMAND_LOOKUP_AREA = 443, + RBAC_PERM_COMMAND_LOOKUP_CREATURE = 444, + RBAC_PERM_COMMAND_LOOKUP_EVENT = 445, + RBAC_PERM_COMMAND_LOOKUP_FACTION = 446, + RBAC_PERM_COMMAND_LOOKUP_ITEM = 447, + RBAC_PERM_COMMAND_LOOKUP_ITEMSET = 448, + RBAC_PERM_COMMAND_LOOKUP_OBJECT = 449, + RBAC_PERM_COMMAND_LOOKUP_QUEST = 450, + RBAC_PERM_COMMAND_LOOKUP_PLAYER = 451, + RBAC_PERM_COMMAND_LOOKUP_PLAYER_IP = 452, + RBAC_PERM_COMMAND_LOOKUP_PLAYER_ACCOUNT = 453, + RBAC_PERM_COMMAND_LOOKUP_PLAYER_EMAIL = 454, + RBAC_PERM_COMMAND_LOOKUP_SKILL = 455, + RBAC_PERM_COMMAND_LOOKUP_SPELL = 456, + RBAC_PERM_COMMAND_LOOKUP_SPELL_ID = 457, + RBAC_PERM_COMMAND_LOOKUP_TAXINODE = 458, + RBAC_PERM_COMMAND_LOOKUP_TELE = 459, + RBAC_PERM_COMMAND_LOOKUP_TITLE = 460, + RBAC_PERM_COMMAND_LOOKUP_MAP = 461, + RBAC_PERM_COMMAND_ANNOUNCE = 462, + RBAC_PERM_COMMAND_CHANNEL = 463, + RBAC_PERM_COMMAND_CHANNEL_SET = 464, + RBAC_PERM_COMMAND_CHANNEL_SET_OWNERSHIP = 465, + RBAC_PERM_COMMAND_GMANNOUNCE = 466, + RBAC_PERM_COMMAND_GMNAMEANNOUNCE = 467, + RBAC_PERM_COMMAND_GMNOTIFY = 468, + RBAC_PERM_COMMAND_NAMEANNOUNCE = 469, + RBAC_PERM_COMMAND_NOTIFY = 470, + RBAC_PERM_COMMAND_WHISPERS = 471, + RBAC_PERM_COMMAND_GROUP = 472, + RBAC_PERM_COMMAND_GROUP_LEADER = 473, + RBAC_PERM_COMMAND_GROUP_DISBAND = 474, + RBAC_PERM_COMMAND_GROUP_REMOVE = 475, + RBAC_PERM_COMMAND_GROUP_JOIN = 476, + RBAC_PERM_COMMAND_GROUP_LIST = 477, + RBAC_PERM_COMMAND_GROUP_SUMMON = 478, + RBAC_PERM_COMMAND_PET = 479, + RBAC_PERM_COMMAND_PET_CREATE = 480, + RBAC_PERM_COMMAND_PET_LEARN = 481, + RBAC_PERM_COMMAND_PET_UNLEARN = 482, + RBAC_PERM_COMMAND_SEND = 483, + RBAC_PERM_COMMAND_SEND_ITEMS = 484, + RBAC_PERM_COMMAND_SEND_MAIL = 485, + RBAC_PERM_COMMAND_SEND_MESSAGE = 486, + RBAC_PERM_COMMAND_SEND_MONEY = 487, + RBAC_PERM_COMMAND_ADDITEM = 488, + RBAC_PERM_COMMAND_ADDITEMSET = 489, + RBAC_PERM_COMMAND_APPEAR = 490, + RBAC_PERM_COMMAND_AURA = 491, + RBAC_PERM_COMMAND_BANK = 492, + RBAC_PERM_COMMAND_BINDSIGHT = 493, + RBAC_PERM_COMMAND_COMBATSTOP = 494, + RBAC_PERM_COMMAND_COMETOME = 495, + RBAC_PERM_COMMAND_COMMANDS = 496, + RBAC_PERM_COMMAND_COOLDOWN = 497, + RBAC_PERM_COMMAND_DAMAGE = 498, + RBAC_PERM_COMMAND_DEV = 499, + RBAC_PERM_COMMAND_DIE = 500, + RBAC_PERM_COMMAND_DISMOUNT = 501, + RBAC_PERM_COMMAND_DISTANCE = 502, + RBAC_PERM_COMMAND_FLUSHARENAPOINTS = 503, + RBAC_PERM_COMMAND_FREEZE = 504, + RBAC_PERM_COMMAND_GPS = 505, + RBAC_PERM_COMMAND_GUID = 506, + RBAC_PERM_COMMAND_HELP = 507, + RBAC_PERM_COMMAND_HIDEAREA = 508, + RBAC_PERM_COMMAND_ITEMMOVE = 509, + RBAC_PERM_COMMAND_KICK = 510, + RBAC_PERM_COMMAND_LINKGRAVE = 511, + RBAC_PERM_COMMAND_LISTFREEZE = 512, + RBAC_PERM_COMMAND_MAXSKILL = 513, + RBAC_PERM_COMMAND_MOVEGENS = 514, + RBAC_PERM_COMMAND_MUTE = 515, + RBAC_PERM_COMMAND_NEARGRAVE = 516, + RBAC_PERM_COMMAND_PINFO = 517, + RBAC_PERM_COMMAND_PLAYALL = 518, + RBAC_PERM_COMMAND_POSSESS = 519, + RBAC_PERM_COMMAND_RECALL = 520, + RBAC_PERM_COMMAND_REPAIRITEMS = 521, + RBAC_PERM_COMMAND_RESPAWN = 522, + RBAC_PERM_COMMAND_REVIVE = 523, + RBAC_PERM_COMMAND_SAVEALL = 524, + RBAC_PERM_COMMAND_SAVE = 525, + RBAC_PERM_COMMAND_SETSKILL = 526, + RBAC_PERM_COMMAND_SHOWAREA = 527, + RBAC_PERM_COMMAND_SUMMON = 528, + RBAC_PERM_COMMAND_UNAURA = 529, + RBAC_PERM_COMMAND_UNBINDSIGHT = 530, + RBAC_PERM_COMMAND_UNFREEZE = 531, + RBAC_PERM_COMMAND_UNMUTE = 532, + RBAC_PERM_COMMAND_UNPOSSESS = 533, + RBAC_PERM_COMMAND_UNSTUCK = 534, + RBAC_PERM_COMMAND_WCHANGE = 535, + RBAC_PERM_COMMAND_MMAP = 536, + RBAC_PERM_COMMAND_MMAP_LOADEDTILES = 537, + RBAC_PERM_COMMAND_MMAP_LOC = 538, + RBAC_PERM_COMMAND_MMAP_PATH = 539, + RBAC_PERM_COMMAND_MMAP_STATS = 540, + RBAC_PERM_COMMAND_MMAP_TESTAREA = 541, + RBAC_PERM_COMMAND_MORPH = 542, + RBAC_PERM_COMMAND_DEMORPH = 543, + RBAC_PERM_COMMAND_MODIFY = 544, + RBAC_PERM_COMMAND_MODIFY_ARENAPOINTS = 545, + RBAC_PERM_COMMAND_MODIFY_BIT = 546, + RBAC_PERM_COMMAND_MODIFY_DRUNK = 547, + RBAC_PERM_COMMAND_MODIFY_ENERGY = 548, + RBAC_PERM_COMMAND_MODIFY_FACTION = 549, + RBAC_PERM_COMMAND_MODIFY_GENDER = 550, + RBAC_PERM_COMMAND_MODIFY_HONOR = 551, + RBAC_PERM_COMMAND_MODIFY_HP = 552, + RBAC_PERM_COMMAND_MODIFY_MANA = 553, + RBAC_PERM_COMMAND_MODIFY_MONEY = 554, + RBAC_PERM_COMMAND_MODIFY_MOUNT = 555, + RBAC_PERM_COMMAND_MODIFY_PHASE = 556, + RBAC_PERM_COMMAND_MODIFY_RAGE = 557, + RBAC_PERM_COMMAND_MODIFY_REPUTATION = 558, + RBAC_PERM_COMMAND_MODIFY_RUNICPOWER = 559, + RBAC_PERM_COMMAND_MODIFY_SCALE = 560, + RBAC_PERM_COMMAND_MODIFY_SPEED = 561, + RBAC_PERM_COMMAND_MODIFY_SPEED_ALL = 562, + RBAC_PERM_COMMAND_MODIFY_SPEED_BACKWALK = 563, + RBAC_PERM_COMMAND_MODIFY_SPEED_FLY = 564, + RBAC_PERM_COMMAND_MODIFY_SPEED_WALK = 565, + RBAC_PERM_COMMAND_MODIFY_SPEED_SWIM = 566, + RBAC_PERM_COMMAND_MODIFY_SPELL = 567, + RBAC_PERM_COMMAND_MODIFY_STANDSTATE = 568, + RBAC_PERM_COMMAND_MODIFY_TALENTPOINTS = 569, + RBAC_PERM_COMMAND_NPC_ADD = 571, + RBAC_PERM_COMMAND_NPC_ADD_FORMATION = 572, + RBAC_PERM_COMMAND_NPC_ADD_ITEM = 573, + RBAC_PERM_COMMAND_NPC_ADD_MOVE = 574, + RBAC_PERM_COMMAND_NPC_ADD_TEMP = 575, + RBAC_PERM_COMMAND_NPC_DELETE = 576, + RBAC_PERM_COMMAND_NPC_DELETE_ITEM = 577, + RBAC_PERM_COMMAND_NPC_FOLLOW = 578, + RBAC_PERM_COMMAND_NPC_FOLLOW_STOP = 579, + RBAC_PERM_COMMAND_NPC_SET = 580, + RBAC_PERM_COMMAND_NPC_SET_ALLOWMOVE = 581, + RBAC_PERM_COMMAND_NPC_SET_ENTRY = 582, + RBAC_PERM_COMMAND_NPC_SET_FACTIONID = 583, + RBAC_PERM_COMMAND_NPC_SET_FLAG = 584, + RBAC_PERM_COMMAND_NPC_SET_LEVEL = 585, + RBAC_PERM_COMMAND_NPC_SET_LINK = 586, + RBAC_PERM_COMMAND_NPC_SET_MODEL = 587, + RBAC_PERM_COMMAND_NPC_SET_MOVETYPE = 588, + RBAC_PERM_COMMAND_NPC_SET_PHASE = 589, + RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST = 590, + RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME = 591, + RBAC_PERM_COMMAND_NPC_SET_DATA = 592, + RBAC_PERM_COMMAND_NPC_INFO = 593, + RBAC_PERM_COMMAND_NPC_NEAR = 594, + RBAC_PERM_COMMAND_NPC_MOVE = 595, + RBAC_PERM_COMMAND_NPC_PLAYEMOTE = 596, + RBAC_PERM_COMMAND_NPC_SAY = 597, + RBAC_PERM_COMMAND_NPC_TEXTEMOTE = 598, + RBAC_PERM_COMMAND_NPC_WHISPER = 599, + RBAC_PERM_COMMAND_NPC_YELL = 600, + RBAC_PERM_COMMAND_NPC_TAME = 601, + RBAC_PERM_COMMAND_QUEST = 602, + RBAC_PERM_COMMAND_QUEST_ADD = 603, + RBAC_PERM_COMMAND_QUEST_COMPLETE = 604, + RBAC_PERM_COMMAND_QUEST_REMOVE = 605, + RBAC_PERM_COMMAND_QUEST_REWARD = 606, + RBAC_PERM_COMMAND_RELOAD = 607, + RBAC_PERM_COMMAND_RELOAD_ACCESS_REQUIREMENT = 608, + RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_CRITERIA_DATA = 609, + RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD = 610, + RBAC_PERM_COMMAND_RELOAD_ALL = 611, + RBAC_PERM_COMMAND_RELOAD_ALL_ACHIEVEMENT = 612, + RBAC_PERM_COMMAND_RELOAD_ALL_AREA = 613, + RBAC_PERM_COMMAND_RELOAD_BROADCAST_TEXT = 614, + RBAC_PERM_COMMAND_RELOAD_ALL_GOSSIP = 615, + RBAC_PERM_COMMAND_RELOAD_ALL_ITEM = 616, + RBAC_PERM_COMMAND_RELOAD_ALL_LOCALES = 617, + RBAC_PERM_COMMAND_RELOAD_ALL_LOOT = 618, + RBAC_PERM_COMMAND_RELOAD_ALL_NPC = 619, + RBAC_PERM_COMMAND_RELOAD_ALL_QUEST = 620, + RBAC_PERM_COMMAND_RELOAD_ALL_SCRIPTS = 621, + RBAC_PERM_COMMAND_RELOAD_ALL_SPELL = 622, + RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_INVOLVEDRELATION = 623, + RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TAVERN = 624, + RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TELEPORT = 625, + RBAC_PERM_COMMAND_RELOAD_AUCTIONS = 626, + RBAC_PERM_COMMAND_RELOAD_AUTOBROADCAST = 627, + RBAC_PERM_COMMAND_RELOAD_CONDITIONS = 629, + RBAC_PERM_COMMAND_RELOAD_CONFIG = 630, + RBAC_PERM_COMMAND_RELOAD_BATTLEGROUND_TEMPLATE = 631, + RBAC_PERM_COMMAND_MUTEHISTORY = 632, + RBAC_PERM_COMMAND_RELOAD_CREATURE_LINKED_RESPAWN = 633, + RBAC_PERM_COMMAND_RELOAD_CREATURE_LOOT_TEMPLATE = 634, + RBAC_PERM_COMMAND_RELOAD_CREATURE_ONKILL_REPUTATION = 635, + RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTENDER = 636, + RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTSTARTER = 637, + RBAC_PERM_COMMAND_RELOAD_CREATURE_SUMMON_GROUPS = 638, + RBAC_PERM_COMMAND_RELOAD_CREATURE_TEMPLATE = 639, + RBAC_PERM_COMMAND_RELOAD_CREATURE_TEXT = 640, + RBAC_PERM_COMMAND_RELOAD_DISABLES = 641, + RBAC_PERM_COMMAND_RELOAD_DISENCHANT_LOOT_TEMPLATE = 642, + RBAC_PERM_COMMAND_RELOAD_EVENT_SCRIPTS = 643, + RBAC_PERM_COMMAND_RELOAD_FISHING_LOOT_TEMPLATE = 644, + RBAC_PERM_COMMAND_RELOAD_GRAVEYARD_ZONE = 645, + RBAC_PERM_COMMAND_RELOAD_GAME_TELE = 646, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER = 647, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE = 648, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER = 649, + RBAC_PERM_COMMAND_RELOAD_GM_TICKETS = 650, + RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU = 651, + RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION = 652, + RBAC_PERM_COMMAND_RELOAD_ITEM_ENCHANTMENT_TEMPLATE = 653, + RBAC_PERM_COMMAND_RELOAD_ITEM_LOOT_TEMPLATE = 654, + RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAMES = 655, + RBAC_PERM_COMMAND_RELOAD_LFG_DUNGEON_REWARDS = 656, + RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD_LOCALE = 657, + RBAC_PERM_COMMAND_RELOAD_CREATURE_TEMPLATE_LOCALE = 658, + RBAC_PERM_COMMAND_RELOAD_CREATURE_TEXT_LOCALE = 659, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE = 660, + RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE = 661, + RBAC_PERM_COMMAND_RELOAD_ITEM_TEMPLATE_LOCALE = 662, + RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAME_LOCALE = 663, + RBAC_PERM_COMMAND_RELOAD_NPC_TEXT_LOCALE = 664, + RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE = 665, + RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST_LOCALE = 666, + RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE_LOCALE = 667, + RBAC_PERM_COMMAND_RELOAD_MAIL_LEVEL_REWARD = 668, + RBAC_PERM_COMMAND_RELOAD_MAIL_LOOT_TEMPLATE = 669, + RBAC_PERM_COMMAND_RELOAD_MILLING_LOOT_TEMPLATE = 670, + RBAC_PERM_COMMAND_RELOAD_NPC_SPELLCLICK_SPELLS = 671, + RBAC_PERM_COMMAND_RELOAD_TRAINER = 672, + RBAC_PERM_COMMAND_RELOAD_NPC_VENDOR = 673, + RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT = 674, + RBAC_PERM_COMMAND_RELOAD_PICKPOCKETING_LOOT_TEMPLATE = 675, + RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST = 676, + RBAC_PERM_COMMAND_RELOAD_PROSPECTING_LOOT_TEMPLATE = 677, + RBAC_PERM_COMMAND_RELOAD_QUEST_POI = 678, + RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE = 679, + RBAC_PERM_COMMAND_RELOAD_RBAC = 680, + RBAC_PERM_COMMAND_RELOAD_REFERENCE_LOOT_TEMPLATE = 681, + RBAC_PERM_COMMAND_RELOAD_RESERVED_NAME = 682, + RBAC_PERM_COMMAND_RELOAD_REPUTATION_REWARD_RATE = 683, + RBAC_PERM_COMMAND_RELOAD_SPILLOVER_TEMPLATE = 684, + RBAC_PERM_COMMAND_RELOAD_SKILL_DISCOVERY_TEMPLATE = 685, + RBAC_PERM_COMMAND_RELOAD_SKILL_EXTRA_ITEM_TEMPLATE = 686, + RBAC_PERM_COMMAND_RELOAD_SKILL_FISHING_BASE_LEVEL = 687, + RBAC_PERM_COMMAND_RELOAD_SKINNING_LOOT_TEMPLATE = 688, + RBAC_PERM_COMMAND_RELOAD_SMART_SCRIPTS = 689, + RBAC_PERM_COMMAND_RELOAD_SPELL_REQUIRED = 690, + RBAC_PERM_COMMAND_RELOAD_SPELL_AREA = 691, + RBAC_PERM_COMMAND_RELOAD_SPELL_BONUS_DATA = 692, + RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP = 693, + RBAC_PERM_COMMAND_RELOAD_SPELL_LEARN_SPELL = 694, + RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695, + RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696, + RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697, + RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT = 698, + RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699, + RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701, + RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS = 702, + RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES = 703, + RBAC_PERM_COMMAND_RELOAD_ACORE_STRING = 704, + RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS = 706, + RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA = 707, + RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESSORY = 708, + RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY = 709, + RBAC_PERM_COMMAND_RESET = 710, + RBAC_PERM_COMMAND_RESET_ACHIEVEMENTS = 711, + RBAC_PERM_COMMAND_RESET_HONOR = 712, + RBAC_PERM_COMMAND_RESET_LEVEL = 713, + RBAC_PERM_COMMAND_RESET_SPELLS = 714, + RBAC_PERM_COMMAND_RESET_STATS = 715, + RBAC_PERM_COMMAND_RESET_TALENTS = 716, + RBAC_PERM_COMMAND_RESET_ALL = 717, + RBAC_PERM_COMMAND_SERVER = 718, + RBAC_PERM_COMMAND_SERVER_CORPSES = 719, + RBAC_PERM_COMMAND_SERVER_EXIT = 720, + RBAC_PERM_COMMAND_SERVER_IDLERESTART = 721, + RBAC_PERM_COMMAND_SERVER_IDLERESTART_CANCEL = 722, + RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN = 723, + RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN_CANCEL = 724, + RBAC_PERM_COMMAND_SERVER_INFO = 725, + RBAC_PERM_COMMAND_SERVER_PLIMIT = 726, + RBAC_PERM_COMMAND_SERVER_RESTART = 727, + RBAC_PERM_COMMAND_SERVER_RESTART_CANCEL = 728, + RBAC_PERM_COMMAND_SERVER_SET = 729, + RBAC_PERM_COMMAND_SERVER_SET_CLOSED = 730, + RBAC_PERM_COMMAND_SERVER_SET_DIFFTIME = 731, + RBAC_PERM_COMMAND_SERVER_SET_LOGLEVEL = 732, + RBAC_PERM_COMMAND_SERVER_SET_MOTD = 733, + RBAC_PERM_COMMAND_SERVER_SHUTDOWN = 734, + RBAC_PERM_COMMAND_SERVER_SHUTDOWN_CANCEL = 735, + RBAC_PERM_COMMAND_SERVER_MOTD = 736, + RBAC_PERM_COMMAND_TELE = 737, + RBAC_PERM_COMMAND_TELE_ADD = 738, + RBAC_PERM_COMMAND_TELE_DEL = 739, + RBAC_PERM_COMMAND_TELE_NAME = 740, + RBAC_PERM_COMMAND_TELE_GROUP = 741, + RBAC_PERM_COMMAND_TICKET = 742, + RBAC_PERM_COMMAND_TICKET_ASSIGN = 743, + RBAC_PERM_COMMAND_TICKET_CLOSE = 744, + RBAC_PERM_COMMAND_TICKET_CLOSEDLIST = 745, + RBAC_PERM_COMMAND_TICKET_COMMENT = 746, + RBAC_PERM_COMMAND_TICKET_COMPLETE = 747, + RBAC_PERM_COMMAND_TICKET_DELETE = 748, + RBAC_PERM_COMMAND_TICKET_ESCALATE = 749, + RBAC_PERM_COMMAND_TICKET_ESCALATEDLIST = 750, + RBAC_PERM_COMMAND_TICKET_LIST = 751, + RBAC_PERM_COMMAND_TICKET_ONLINELIST = 752, + RBAC_PERM_COMMAND_TICKET_RESET = 753, + RBAC_PERM_COMMAND_TICKET_RESPONSE = 754, + RBAC_PERM_COMMAND_TICKET_RESPONSE_APPEND = 755, + RBAC_PERM_COMMAND_TICKET_RESPONSE_APPENDLN = 756, + RBAC_PERM_COMMAND_TICKET_TOGGLESYSTEM = 757, + RBAC_PERM_COMMAND_TICKET_UNASSIGN = 758, + RBAC_PERM_COMMAND_TICKET_VIEWID = 759, + RBAC_PERM_COMMAND_TICKET_VIEWNAME = 760, + RBAC_PERM_COMMAND_TITLES_ADD = 762, + RBAC_PERM_COMMAND_TITLES_CURRENT = 763, + RBAC_PERM_COMMAND_TITLES_REMOVE = 764, + RBAC_PERM_COMMAND_TITLES_SET_MASK = 766, + RBAC_PERM_COMMAND_WP = 767, + RBAC_PERM_COMMAND_WP_ADD = 768, + RBAC_PERM_COMMAND_WP_EVENT = 769, + RBAC_PERM_COMMAND_WP_LOAD = 770, + RBAC_PERM_COMMAND_WP_MODIFY = 771, + RBAC_PERM_COMMAND_WP_UNLOAD = 772, + RBAC_PERM_COMMAND_WP_RELOAD = 773, + RBAC_PERM_COMMAND_WP_SHOW = 774, + RBAC_PERM_COMMAND_MAILBOX = 777, + RBAC_PERM_COMMAND_AHBOT_ITEMS = 779, + RBAC_PERM_COMMAND_AHBOT_ITEMS_GRAY = 780, + RBAC_PERM_COMMAND_AHBOT_ITEMS_WHITE = 781, + RBAC_PERM_COMMAND_AHBOT_ITEMS_GREEN = 782, + RBAC_PERM_COMMAND_AHBOT_ITEMS_BLUE = 783, + RBAC_PERM_COMMAND_AHBOT_ITEMS_PURPLE = 784, + RBAC_PERM_COMMAND_AHBOT_ITEMS_ORANGE = 785, + RBAC_PERM_COMMAND_AHBOT_ITEMS_YELLOW = 786, + RBAC_PERM_COMMAND_AHBOT_RATIO = 787, + RBAC_PERM_COMMAND_AHBOT_RATIO_ALLIANCE = 788, + RBAC_PERM_COMMAND_AHBOT_RATIO_HORDE = 789, + RBAC_PERM_COMMAND_AHBOT_RATIO_NEUTRAL = 790, + RBAC_PERM_COMMAND_AHBOT_REBUILD = 791, + RBAC_PERM_COMMAND_AHBOT_RELOAD = 792, + RBAC_PERM_COMMAND_AHBOT_STATUS = 793, + RBAC_PERM_COMMAND_GUILD_INFO = 794, + RBAC_PERM_COMMAND_INSTANCE_SET_BOSS_STATE = 795, + RBAC_PERM_COMMAND_INSTANCE_GET_BOSS_STATE = 796, + RBAC_PERM_COMMAND_PVPSTATS = 797, + RBAC_PERM_COMMAND_MODIFY_XP = 798, + RBAC_PERM_COMMAND_NPC_EVADE = 837, + RBAC_PERM_COMMAND_PET_LEVEL = 838, + RBAC_PERM_COMMAND_SERVER_SHUTDOWN_FORCE = 839, + RBAC_PERM_COMMAND_SERVER_RESTART_FORCE = 840, + RBAC_PERM_COMMAND_NEARGRAVEYARD = 841, + RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING = 843, + RBAC_PERM_COMMAND_NPC_SPAWNGROUP = 856, + RBAC_PERM_COMMAND_NPC_DESPAWNGROUP = 857, + RBAC_PERM_COMMAND_GOBJECT_SPAWNGROUP = 858, + RBAC_PERM_COMMAND_GOBJECT_DESPAWNGROUP = 859, + RBAC_PERM_COMMAND_LIST_RESPAWNS = 860, + RBAC_PERM_COMMAND_GROUP_SET = 861, + RBAC_PERM_COMMAND_GROUP_ASSISTANT = 862, + RBAC_PERM_COMMAND_GROUP_MAINTANK = 863, + RBAC_PERM_COMMAND_GROUP_MAINASSIST = 864, + RBAC_PERM_COMMAND_GROUP_REVIVE = 868, + RBAC_PERM_COMMAND_NPC_SHOWLOOT = 865, + RBAC_PERM_COMMAND_LIST_SPAWNPOINTS = 866, + RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING_LOCALE = 867, + RBAC_PERM_COMMAND_SERVER_DEBUG = 872, + RBAC_PERM_COMMAND_RELOAD_CREATURE_MOVEMENT_OVERRIDE = 873, + RBAC_PERM_COMMAND_SETTINGS_ANNOUNCER = 874, + RBAC_PERM_COMMAND_LOOKUP_MAP_ID = 875, + RBAC_PERM_COMMAND_LOOKUP_ITEM_ID = 876, + RBAC_PERM_COMMAND_LOOKUP_QUEST_ID = 877, + RBAC_PERM_COMMAND_PDUMP_COPY = 880, + RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE = 881, + RBAC_PERM_COMMAND_BG_START = 884, + RBAC_PERM_COMMAND_BG_STOP = 885, + RBAC_PERM_COMMAND_ITEM_RESTORE = 886, + RBAC_PERM_COMMAND_ITEM_RESTORE_LIST = 887, + RBAC_PERM_COMMAND_ITEM_REFUND = 888, + RBAC_PERM_COMMAND_COMMENTATOR = 889, + RBAC_PERM_COMMAND_SKIRMISH = 890, + RBAC_PERM_COMMAND_STRING = 891, + RBAC_PERM_COMMAND_OPENDOOR = 892, + RBAC_PERM_COMMAND_BEASTMASTER = 893, + RBAC_PERM_COMMAND_PACKETLOG = 894, + RBAC_PERM_COMMAND_AURA_STACK = 895, + RBAC_PERM_COMMAND_RESPAWN_ALL = 896, + RBAC_PERM_COMMAND_GEAR_REPAIR = 897, + RBAC_PERM_COMMAND_GEAR_STATS = 898, + RBAC_PERM_COMMAND_SPECT = 899, + RBAC_PERM_COMMAND_SPECT_VERSION = 900, + RBAC_PERM_COMMAND_SPECT_RESET = 901, + RBAC_PERM_COMMAND_SPECT_SPECTATE = 902, + RBAC_PERM_COMMAND_SPECT_WATCH = 903, + RBAC_PERM_COMMAND_SPECT_LEAVE = 904, + RBAC_PERM_COMMAND_ARENA_SEASON = 905, + RBAC_PERM_COMMAND_ARENA_SEASON_REWARD = 906, + RBAC_PERM_COMMAND_ARENA_SEASON_DELETETEAMS = 907, + RBAC_PERM_COMMAND_ARENA_SEASON_START = 908, + RBAC_PERM_COMMAND_CHARACTER_CHECK_BANK = 909, + RBAC_PERM_COMMAND_CHARACTER_CHECK_BAG = 910, + RBAC_PERM_COMMAND_CHARACTER_CHECK_PROFESSION = 911, + RBAC_PERM_COMMAND_GOBJECT_LOAD = 912, + RBAC_PERM_COMMAND_BF_QUEUE = 913, + // custom permissions 1000+ + RBAC_PERM_MAX +}; + +enum RBACCommandResult +{ + RBAC_OK, + RBAC_CANT_ADD_ALREADY_ADDED, + RBAC_CANT_REVOKE_NOT_IN_LIST, + RBAC_IN_GRANTED_LIST, + RBAC_IN_DENIED_LIST, + RBAC_ID_DOES_NOT_EXISTS +}; + +typedef std::set RBACPermissionContainer; + +class AC_GAME_API RBACPermission +{ +public: + RBACPermission(uint32 id = 0, std::string const& name = ""): + _id(id), _name(name), _perms() { } + + /// Gets the Name of the Object + std::string const& GetName() const { return _name; } + /// Gets the Id of the Object + uint32 GetId() const { return _id; } + + /// Gets the Permissions linked to this permission + RBACPermissionContainer const& GetLinkedPermissions() const { return _perms; } + /// Adds a new linked Permission + void AddLinkedPermission(uint32 id) { _perms.insert(id); } + /// Removes a linked Permission + void RemoveLinkedPermission(uint32 id) { _perms.erase(id); } + +private: + uint32 _id; ///> id of the object + std::string _name; ///> name of the object + RBACPermissionContainer _perms; ///> Set of permissions +}; + +/** + * @name RBACData + * @brief Contains all needed information about the account + * + * This class contains all the data needed to calculate the account permissions. + * RBACData is formed by granted and denied permissions and all the inherited permissions + * + * Calculation of current Permissions: Granted permissions - Denied permissions + * - Granted permissions: through linked permissions and directly assigned + * - Denied permissions: through linked permissions and directly assigned + */ +class AC_GAME_API RBACData +{ +public: + RBACData(uint32 id, std::string const& name, int32 realmId, uint8 secLevel = 255): + _id(id), _name(name), _realmId(realmId), _secLevel(secLevel), + _grantedPerms(), _deniedPerms(), _globalPerms() { } + + /// Gets the Name of the Object + std::string const& GetName() const { return _name; } + /// Gets the Id of the Object + uint32 GetId() const { return _id; } + + /** + * @name HasPermission + * @brief Checks if certain action is allowed + * + * @return grant or deny action + */ + bool HasPermission(uint32 permission) const + { + return _globalPerms.find(permission) != _globalPerms.end(); + } + + // Functions enabled to be used by command system + /// Returns all the granted permissions (after computation) + RBACPermissionContainer const& GetPermissions() const { return _globalPerms; } + /// Returns all the granted permissions + RBACPermissionContainer const& GetGrantedPermissions() const { return _grantedPerms; } + /// Returns all the denied permissions + RBACPermissionContainer const& GetDeniedPermissions() const { return _deniedPerms; } + + /** + * @name GrantPermission + * @brief Grants a permission + * + * @param permissionId permission to be granted + * @param realmId realm affected + * + * @return Success or failure (with reason) to grant the permission + */ + RBACCommandResult GrantPermission(uint32 permissionId, int32 realmId = 0); + + /** + * @name DenyPermission + * @brief Denies a permission + * + * @param permissionId permission to be denied + * @param realmId realm affected + * + * @return Success or failure (with reason) to deny the permission + */ + RBACCommandResult DenyPermission(uint32 permissionId, int32 realmId = 0); + + /** + * @name RevokePermission + * @brief Removes a permission + * + * @param permissionId permission to be removed + * @param realmId realm affected + * + * @return Success or failure (with reason) to remove the permission + */ + RBACCommandResult RevokePermission(uint32 permissionId, int32 realmId = 0); + + /// Loads all permissions assigned to current account + void LoadFromDB(); + QueryCallback LoadFromDBAsync(); + void LoadFromDBCallback(PreparedQueryResult result); + + /// Sets security level + void SetSecurityLevel(uint8 id) + { + _secLevel = id; + LoadFromDB(); + } + + /// Returns the security level assigned + uint8 GetSecurityLevel() const { return _secLevel; } + + /// For unit testing - forces permission recalculation without database + void RecalculatePermissions() { CalculateNewPermissions(); } + + /// For unit testing - sets security level without database reload + void SetSecurityLevelForTest(uint8 id) { _secLevel = id; } + +private: + /// Saves a permission to DB, Granted or Denied + void SavePermission(uint32 role, bool granted, int32 realm); + /// Clears roles, groups and permissions - Used for reload + void ClearData(); + + /** + * @name CalculateNewPermissions + * @brief Calculates new permissions + * + * Calculates new permissions after some change + * The calculation is done Granted - Denied: + * - Granted permissions: through linked permissions and directly assigned + * - Denied permissions: through linked permissions and directly assigned + */ + void CalculateNewPermissions(); + + int32 GetRealmId() const { return _realmId; } + + /// Checks if a permission is granted + bool HasGrantedPermission(uint32 permissionId) const + { + return _grantedPerms.find(permissionId) != _grantedPerms.end(); + } + + /// Checks if a permission is denied + bool HasDeniedPermission(uint32 permissionId) const + { + return _deniedPerms.find(permissionId) != _deniedPerms.end(); + } + + /// Adds a new granted permission + void AddGrantedPermission(uint32 permissionId) + { + _grantedPerms.insert(permissionId); + } + + /// Removes a granted permission + void RemoveGrantedPermission(uint32 permissionId) + { + _grantedPerms.erase(permissionId); + } + + /// Adds a new denied permission + void AddDeniedPermission(uint32 permissionId) + { + _deniedPerms.insert(permissionId); + } + + /// Removes a denied permission + void RemoveDeniedPermission(uint32 permissionId) + { + _deniedPerms.erase(permissionId); + } + + /// Adds a list of permissions to another list + void AddPermissions(RBACPermissionContainer const& permsFrom, RBACPermissionContainer& permsTo); + + /// Removes a list of permissions from another list + void RemovePermissions(RBACPermissionContainer& permsFrom, RBACPermissionContainer const& permsToRemove); + + /** + * @name ExpandPermissions + * @brief Adds the list of linked permissions to the original list + * + * @param permissions The list of permissions to expand + */ + void ExpandPermissions(RBACPermissionContainer& permissions); + + uint32 _id; ///> Account id + std::string _name; ///> Account name + int32 _realmId; ///> RealmId Affected + uint8 _secLevel; ///> Account SecurityLevel + RBACPermissionContainer _grantedPerms; ///> Granted permissions + RBACPermissionContainer _deniedPerms; ///> Denied permissions + RBACPermissionContainer _globalPerms; ///> Calculated permissions +}; + +} + +#endif diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 29628f1f8..f0aa9da38 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -40,6 +40,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "RaceMgr.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -520,6 +521,8 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaCondition condi // disable for gamemasters with GM-mode enabled if (_player->IsGameMaster()) return; + if (_player->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS)) + return; LOG_DEBUG("achievement", "AchievementMgr::ResetAchievementCriteria({}, {}, {})", condition, value, evenIfCriteriaComplete); @@ -821,6 +824,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // disable for gamemasters with GM-mode enabled if (_player->IsGameMaster()) return; + if (_player->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS)) + return; if (type >= ACHIEVEMENT_CRITERIA_TYPE_TOTAL) { @@ -2282,6 +2287,8 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) ChatHandler(_player->GetSession()).PSendSysMessage("Not available in GM mode"); return; } + if (_player->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS)) + return; if (!sScriptMgr->OnPlayerBeforeAchievementComplete(GetPlayer(), achievement)) { @@ -2323,7 +2330,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) } } - if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL) && AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity())) + if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL) && !_player->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_REALM_FIRST_ACHIEVEMENTS)) sAchievementMgr->SetRealmCompleted(achievement); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID); diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index c72f94394..ad6d74523 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -39,6 +39,7 @@ #include "ObjectMgr.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "SpellAuras.h" @@ -1110,7 +1111,7 @@ void Battleground::RemovePlayerAtLeave(Player* player) SendPacketToTeam(teamId, &data, player, false); // cast deserter - if (isBattleground() && !player->IsGameMaster() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_CAST_DESERTER)) + if (isBattleground() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_NO_BATTLEGROUND_DESERTER_DEBUFF) && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_CAST_DESERTER)) if (status == STATUS_IN_PROGRESS || status == STATUS_WAIT_JOIN) player->ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 05e887a6b..ad7b9dfc9 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -23,6 +23,7 @@ #include "GameTime.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "SocialMgr.h" #include "World.h" @@ -218,7 +219,7 @@ void Channel::JoinChannel(Player* player, std::string const& pass) JoinNotify(player); - playersStore[guid].SetOwnerGM(player->GetSession()->IsGMAccount()); + playersStore[guid].SetOwnerGM(player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)); // Custom channel handling if (!IsConstant()) @@ -296,11 +297,11 @@ void Channel::LeaveChannel(Player* player, bool send) for (Channel::PlayerContainer::const_iterator itr = playersStore.begin(); itr != playersStore.end(); ++itr) { newowner = itr->second.player; - if (itr->second.plrPtr->GetSession()->IsGMAccount()) + if (itr->second.plrPtr->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) _isOwnerGM = true; else _isOwnerGM = false; - if (!itr->second.plrPtr->GetSession()->GetSecurity()) + if (!itr->second.plrPtr->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) break; } SetOwner(newowner); @@ -324,7 +325,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b return; } - if (!playersStore[good].IsModerator() && !player->GetSession()->IsGMAccount()) + if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -347,7 +348,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b bool isOnChannel = victim && IsOn(victim); if (!isOnChannel) { - if (ban && (player->GetSession()->IsGMAccount() || isGoodConstantModerator)) + if (ban && (player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) || isGoodConstantModerator)) { if (ObjectGuid guid = sCharacterCache->GetCharacterGuidByName(badname)) { @@ -387,7 +388,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b bool changeowner = _ownerGUID == victim; bool isBadConstantModerator = _channelRights.moderators.find(badAccId) != _channelRights.moderators.end(); - if (!player->GetSession()->IsGMAccount() && !isGoodConstantModerator) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && !isGoodConstantModerator) { if (changeowner && good != _ownerGUID) { @@ -405,7 +406,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b return; } - if (isBadConstantModerator || bad->GetSession()->IsGMAccount()) + if (isBadConstantModerator || bad->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -454,7 +455,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b for (Channel::PlayerContainer::const_iterator itr = playersStore.begin(); itr != playersStore.end(); ++itr) { newowner = itr->second.player; - if (!itr->second.plrPtr->GetSession()->GetSecurity()) + if (!itr->second.plrPtr->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) break; } SetOwner(newowner); @@ -476,7 +477,7 @@ void Channel::UnBan(Player const* player, std::string const& badname) return; } - if (!playersStore[good].IsModerator() && !player->GetSession()->IsGMAccount()) + if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -499,7 +500,7 @@ void Channel::UnBan(Player const* player, std::string const& badname) } bool isConstantModerator = _channelRights.moderators.find(player->GetSession()->GetAccountId()) != _channelRights.moderators.end(); - if (!player->GetSession()->IsGMAccount() && !isConstantModerator) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && !isConstantModerator) { if (_channelRights.flags & CHANNEL_RIGHT_CANT_BAN) { @@ -544,7 +545,7 @@ void Channel::Password(Player const* player, std::string const& pass) return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->IsGMAccount()) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -581,7 +582,7 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->IsGMAccount()) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -598,7 +599,7 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo if (!victim || !IsOn(victim) || // allow make moderator from another team only if both is GMs // at this moment this only way to show channel post for GM from another team - ((!player->GetSession()->IsGMAccount() || !newp->GetSession()->IsGMAccount()) && player->GetTeamId() != newp->GetTeamId() && + ((!player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || !newp->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)) && player->GetTeamId() != newp->GetTeamId() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))) { WorldPacket data; @@ -624,7 +625,7 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo else { bool isGoodConstantModerator = _channelRights.moderators.find(player->GetSession()->GetAccountId()) != _channelRights.moderators.end(); - if (!player->GetSession()->IsGMAccount() && !isGoodConstantModerator) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && !isGoodConstantModerator) { if (_channelRights.flags & CHANNEL_RIGHT_CANT_MUTE) { @@ -652,7 +653,7 @@ void Channel::SetOwner(Player const* player, std::string const& newname) } bool isGoodConstantModerator = _channelRights.moderators.find(player->GetSession()->GetAccountId()) != _channelRights.moderators.end(); - if (!player->GetSession()->IsGMAccount() && guid != _ownerGUID && !isGoodConstantModerator) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && guid != _ownerGUID && !isGoodConstantModerator) { WorldPacket data; MakeNotOwner(&data); @@ -706,15 +707,20 @@ void Channel::List(Player const* player) std::size_t pos = data.wpos(); data << uint32(0); // size of list, placeholder + uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); + uint32 count = 0; if (!(_channelRights.flags & CHANNEL_RIGHT_CANT_SPEAK)) for (PlayerContainer::const_iterator i = playersStore.begin(); i != playersStore.end(); ++i) - if (AccountMgr::IsPlayerAccount(i->second.plrPtr->GetSession()->GetSecurity())) - { - data << i->first; - data << uint8(i->second.flags); // flags seems to be changed... - ++count; - } + if (Player* member = i->second.plrPtr) + if ((player->GetSession()->HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) || + member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) && + member->IsVisibleGloballyFor(player)) + { + data << i->first; + data << uint8(i->second.flags); // flags seems to be changed... + ++count; + } data.put(pos, count); @@ -733,7 +739,7 @@ void Channel::Announce(Player const* player) return; } - if (!playersStore[guid].IsModerator() && !player->GetSession()->IsGMAccount()) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -932,7 +938,7 @@ void Channel::SendToAllWatching(WorldPacket* data) bool Channel::ShouldAnnouncePlayer(Player const* player) const { - return !(player->GetSession()->IsGMAccount() && sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL)); + return !(player->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL) && sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL)); } void Channel::Voice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) @@ -1158,7 +1164,7 @@ void Channel::JoinNotify(Player* p) { if (_channelRights.flags & CHANNEL_RIGHT_CANT_SPEAK) return; - if (!AccountMgr::IsPlayerAccount(p->GetSession()->GetSecurity())) + if (p->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) return; WorldPacket data(SMSG_USERLIST_ADD, 8 + 1 + 1 + 4 + GetName().size()); @@ -1175,7 +1181,7 @@ void Channel::LeaveNotify(Player* p) { if (_channelRights.flags & CHANNEL_RIGHT_CANT_SPEAK) return; - if (!AccountMgr::IsPlayerAccount(p->GetSession()->GetSecurity())) + if (p->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) return; WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size()); @@ -1191,7 +1197,7 @@ void Channel::FlagsNotify(Player* p) { if (_channelRights.flags & CHANNEL_RIGHT_CANT_SPEAK) return; - if (!AccountMgr::IsPlayerAccount(p->GetSession()->GetSecurity())) + if (p->GetSession()->HasPermission(rbac::RBAC_PERM_SILENTLY_JOIN_CHANNEL)) return; WorldPacket data(SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size()); @@ -1230,8 +1236,7 @@ void Channel::ToggleModeration(Player* player) return; } - const AccountTypes level = static_cast(sWorld->getIntConfig(CONFIG_GM_LEVEL_CHANNEL_MODERATION)); - const bool gm = (player->GetSession()->GetSecurity() >= level); + const bool gm = player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR); if (!playersStore[guid].IsModerator() && !gm) { diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 33892e072..097017d73 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -24,6 +24,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "Realm.h" #include "ScriptMgr.h" #include "Tokenize.h" @@ -54,6 +55,13 @@ bool ChatHandler::IsAvailable(uint32 securityLevel) const return IsConsole() ? true : m_session->GetSecurity() >= AccountTypes(securityLevel); } +bool ChatHandler::HasPermission(uint32 permissionId) const +{ + if (IsConsole()) + return true; + return m_session && m_session->HasPermission(permissionId); +} + bool ChatHandler::HasLowerSecurity(Player* target, ObjectGuid guid, bool strong) { WorldSession* target_session = nullptr; @@ -82,7 +90,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac return false; // ignore only for non-players for non strong checks (when allow apply command at least to same sec level) - if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !strong && sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY)) + if (m_session->HasPermission(rbac::RBAC_PERM_CAN_IGNORE_LOWER_SECURITY_CHECK) && !strong && sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY)) return false; if (target) @@ -117,7 +125,7 @@ void ChatHandler::SendGMText(std::string_view str) { std::vector lines = Acore::Tokenize(str, '\n', true); // Session should have permissions to receive global gm messages - if (AccountMgr::IsPlayerAccount(m_session->GetSecurity())) + if (!m_session->HasPermission(rbac::RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE)) return; for (std::string_view line : lines) @@ -231,7 +239,7 @@ bool ChatHandler::_ParseCommands(std::string_view text) return true; // Pretend commands don't exist for regular players - if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS)) + if (m_session && !m_session->HasPermission(rbac::RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS)) return false; // Send error message for GMs @@ -358,7 +366,7 @@ std::size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, La if (Player const* playerSender = sender->ToPlayer()) { chatTag = playerSender->GetChatTag(); - gmMessage = playerSender->IsGameMaster(); + gmMessage = playerSender->GetSession()->HasPermission(rbac::RBAC_PERM_COMMAND_GM_CHAT); } } diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index ce733b3a5..59a41f79a 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -248,6 +248,7 @@ public: Player* GetPlayer() const; WorldSession* GetSession() { return m_session; } bool IsAvailable(uint32 securityLevel) const; + bool HasPermission(uint32 permissionId) const; protected: explicit ChatHandler() : m_session(nullptr), sentErrorMessage(false) {} // for CLI subclass diff --git a/src/server/game/Chat/ChatCommands/ChatCommand.cpp b/src/server/game/Chat/ChatCommands/ChatCommand.cpp index 0e763f1b3..6e72f54aa 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommand.cpp +++ b/src/server/game/Chat/ChatCommands/ChatCommand.cpp @@ -22,6 +22,7 @@ #include "DatabaseEnv.h" #include "Log.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "StringFormat.h" #include "Tokenize.h" @@ -515,6 +516,10 @@ bool Acore::Impl::ChatCommands::ChatCommandNode::IsInvokerVisible(ChatHandler co if (who.IsConsole() && (_permission.AllowConsole == Acore::ChatCommands::Console::Yes)) return true; + // RBAC permissions start at 200, SEC_* levels are 0-4 + if (_permission.RequiredLevel >= rbac::RBAC_PERM_COMMAND_RBAC) + return who.HasPermission(_permission.RequiredLevel); + return !who.IsConsole() && who.IsAvailable(_permission.RequiredLevel); } diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 9da1f9199..5422da2ec 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -34,6 +34,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "SharedDefines.h" #include "SocialMgr.h" @@ -493,7 +494,9 @@ namespace lfg uint32 lockData = 0; - if (dungeon->expansion > expansion || (onlySeasonalBosses && !dungeon->seasonal)) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_DUNGEON_FINDER)) + lockData = LFG_LOCKSTATUS_RAID_LOCKED; + else if (dungeon->expansion > expansion || (onlySeasonalBosses && !dungeon->seasonal)) lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (IsDungeonDisabled(dungeon->map, dungeon->difficulty)) lockData = LFG_LOCKSTATUS_RAID_LOCKED; @@ -698,7 +701,11 @@ namespace lfg if (!isRaid && joinData.result == LFG_JOIN_OK) { // Check player or group member restrictions - if (player->InBattleground() || (player->InBattlegroundQueue() && !sWorld->getBoolConfig(CONFIG_ALLOW_JOIN_BG_AND_LFG))) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_DUNGEON_FINDER)) + { + joinData.result = LFG_JOIN_NOT_MEET_REQS; + } + else if (player->InBattleground() || (player->InBattlegroundQueue() && !sWorld->getBoolConfig(CONFIG_ALLOW_JOIN_BG_AND_LFG))) { joinData.result = LFG_JOIN_USING_BG_SYSTEM; } @@ -721,7 +728,11 @@ namespace lfg { if (Player* plrg = itr->GetSource()) { - if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER)) + if (!plrg->GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_DUNGEON_FINDER)) + { + joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS; + } + else if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER)) { joinData.result = LFG_JOIN_PARTY_DESERTER; } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 63af9c9a6..4537b5e0f 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2054,10 +2054,6 @@ void Creature::Respawn(bool force) if (getDeathState() == DeathState::Dead) { - // TempSummons (no m_spawnId) shouldn't be resurrected here; TempSummon::Update UnSummons them on the next tick once deathState is Dead. - if (!m_spawnId && !force) - return; - if (m_spawnId) { GetMap()->RemoveCreatureRespawnTime(m_spawnId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c7e6dc6d8..a74c0c0d6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -66,6 +66,7 @@ #include "Pet.h" #include "PetitionMgr.h" #include "QuestDef.h" +#include "RBAC.h" #include "Realm.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -175,7 +176,7 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), _cinematicMgr(*thi //m_pad = 0; // players always accept - if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) SetAcceptWhispers(true); m_usedTalentCount = 0; @@ -573,7 +574,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (GetSession()->HasPermission(rbac::RBAC_PERM_USE_START_GM_LEVEL)) { uint32 gm_level = sWorld->getIntConfig(CONFIG_START_GM_LEVEL); if (gm_level > start_level) @@ -1312,7 +1313,7 @@ void Player::ToggleAFK() ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); // afk player not allowed in battleground - if (!IsGameMaster() && isAFK() && InBattleground()) + if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_AFK_ON_BATTLEGROUND) && isAFK() && InBattleground() && !InArena()) LeaveBattleground(); } @@ -1358,7 +1359,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return false; } - if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sDisableMgr->IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) + if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_DISABLE_MAP) && sDisableMgr->IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) { LOG_ERROR("entities.player", "Player ({}, name: {}) tried to enter a forbidden map {}", GetGUID().ToString(), GetName(), mapid); SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED); @@ -2188,6 +2189,11 @@ bool Player::IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta) cons return true; } +bool Player::CanBeGameMaster() const +{ + return GetSession()->HasPermission(rbac::RBAC_PERM_COMMAND_GM); +} + void Player::SetGameMaster(bool on) { if (on) @@ -2540,10 +2546,15 @@ void Player::InitTalentForLevel() { uint32 talentPointsForLevel = CalculateTalentsPoints(); - // xinef: more talent points that we have are used, reset + // if used more than have then reset if (m_usedTalentCount > talentPointsForLevel) - resetTalents(true); - // xinef: else, recalculate free talent points count + { + if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED)) + resetTalents(true); + else + SetFreeTalentPoints(0); + } + // else update amount of free points else SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount); @@ -9436,7 +9447,7 @@ void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/, SendDirectMessage(&data); // Special handling for messages, do not use visibility map for stealthed units - Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE), nullptr, true); + Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT), nullptr, true); Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); } @@ -11302,13 +11313,17 @@ void Player::LeaveBattleground(Battleground* bg) TeleportToEntryPoint(); } -bool Player::CanJoinToBattleground() const +bool Player::CanJoinToBattleground(Battleground const* bg) const { // check Deserter debuff if (HasAura(26013)) return false; - return true; + if (bg->isArena()) + return GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_ARENAS); + if (bg->GetBgTypeID() == BATTLEGROUND_RB) + return GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_RANDOM_BG); + return GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_NORMAL_BG); } bool Player::CanReportAfkDueToLimit() @@ -12560,8 +12575,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons return true; // Keep active non-passive auras (e.g. Shield Wall) when disarmed - Item* offhand = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (!spellInfo->IsPassive() && offhand && offhand != ignoreItem) + if (!spellInfo->IsPassive() && HasAuraType(SPELL_AURA_MOD_DISARM_OFFHAND) && GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (spellInfo->Effects[i].IsAura()) @@ -12763,7 +12777,9 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar if (!pRewardSource) return; - ObjectGuid creature_guid = (pRewardSource->IsCreature()) ? pRewardSource->GetGUID() : ObjectGuid::Empty; + ObjectGuid creature_guid; + if (pRewardSource->IsCreature() && pRewardSource->GetEntry() == creature_id) + creature_guid = pRewardSource->GetGUID(); // prepare data for near group iteration if (Group* group = GetGroup()) @@ -14353,6 +14369,9 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const bool Player::CanSeeObjectByVisibilityConditions(WorldObject const* object) const { + if (IsGameMaster()) + return true; + ConditionList conds = sConditionMgr->GetConditionsForObjectVisibility(object); ConditionSourceInfo info = ConditionSourceInfo(const_cast(this), const_cast(object)); return sConditionMgr->IsObjectMeetToConditions(info, conds); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d4112c178..5b85e3d73 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1172,6 +1172,7 @@ public: [[nodiscard]] bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } void SetAcceptWhispers(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } [[nodiscard]] bool IsGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; } + [[nodiscard]] bool CanBeGameMaster() const; void SetGameMaster(bool on); [[nodiscard]] bool isGMChat() const { return m_ExtraFlags & PLAYER_EXTRA_GM_CHAT; } void SetGMChat(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; } @@ -2317,7 +2318,7 @@ public: [[nodiscard]] TeamId GetBgTeamId() const { return m_bgData.bgTeamId != TEAM_NEUTRAL ? m_bgData.bgTeamId : GetTeamId(); } void LeaveBattleground(Battleground* bg = nullptr); - [[nodiscard]] bool CanJoinToBattleground() const; + [[nodiscard]] bool CanJoinToBattleground(Battleground const* bg) const; bool CanReportAfkDueToLimit(); void ReportedAfkBy(Player* reporter); void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); } diff --git a/src/server/game/Entities/Player/PlayerMisc.cpp b/src/server/game/Entities/Player/PlayerMisc.cpp index 91459d848..91a3fa93c 100644 --- a/src/server/game/Entities/Player/PlayerMisc.cpp +++ b/src/server/game/Entities/Player/PlayerMisc.cpp @@ -20,6 +20,7 @@ #include "InstancePackets.h" #include "MapMgr.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "WorldSession.h" @@ -30,7 +31,7 @@ void Player::UpdateSpeakTime(ChatFloodThrottle::Index index) { // ignore chat spam protection for GMs in any mode - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_SPAM)) return; uint32 limit, delay; diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index e81d68d98..adc924fe2 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -49,6 +49,7 @@ #include "Player.h" #include "QueryHolder.h" #include "QuestDef.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "ScriptObjectFwd.h" @@ -5049,7 +5050,9 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons m_name = fields[2].Get(); // check name limitations - if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS) + uint8 nameResult = ObjectMgr::CheckPlayerName(m_name); + if (nameResult != CHAR_NAME_SUCCESS && + !(nameResult == CHAR_NAME_RESERVED && GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME))) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->SetData(0, uint16(AT_LOGIN_RENAME)); @@ -5593,7 +5596,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons outDebugValues(); // GM state - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (GetSession()->HasPermission(rbac::RBAC_PERM_RESTORE_SAVED_GM_STATE)) { switch (sWorld->getIntConfig(CONFIG_GM_LOGIN_STATE)) { diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index ed59470dd..46fc3a416 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -20,6 +20,7 @@ #include "DatabaseEnv.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "Util.h" #include "WorldPacket.h" #include "WorldSession.h" @@ -224,8 +225,6 @@ void SocialMgr::GetFriendInfo(Player* player, ObjectGuid const& friendGUID, Frie return; TeamId teamId = player->GetTeamId(); - AccountTypes security = player->GetSession()->GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); auto const& itr = player->GetSocial()->m_playerSocialMap.find(friendGUID); @@ -234,7 +233,14 @@ void SocialMgr::GetFriendInfo(Player* player, ObjectGuid const& friendGUID, Frie // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if ((!AccountMgr::IsPlayerAccount(security) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) && pFriend->IsVisibleGloballyFor(player)) + if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && + pFriend->GetSession()->GetSecurity() > gmLevelInWhoList) + return; + + if (pFriend->GetTeamId() != teamId && !player->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST)) + return; + + if (pFriend->IsVisibleGloballyFor(player)) { friendInfo.Status = FRIEND_STATUS_ONLINE; if (pFriend->isAFK()) @@ -297,8 +303,6 @@ void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet) return; TeamId teamId = player->GetTeamId(); - AccountTypes security = player->GetSession()->GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); for (auto const& itr : m_socialMap) @@ -307,10 +311,19 @@ void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet) if (itr2 != itr.second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND)) { Player* pFriend = ObjectAccessor::FindPlayer(itr.first); + if (!pFriend) + continue; + WorldSession* session = pFriend->GetSession(); // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (pFriend && (!AccountMgr::IsPlayerAccount(pFriend->GetSession()->GetSecurity()) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && security <= gmLevelInWhoList)) && player->IsVisibleGloballyFor(pFriend)) + if (!session->HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && player->GetSession()->GetSecurity() > gmLevelInWhoList) + continue; + + if (pFriend->GetTeamId() != teamId && !session->HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST)) + continue; + + if (player->IsVisibleGloballyFor(pFriend)) pFriend->SendDirectMessage(packet); } } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5ed5ac6db..7a0049d2b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1229,7 +1229,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage { uint32 unDamage = health < damage ? health : damage; bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr - || attacker->GetCharmerOrOwnerGUID().IsPlayer()); + || attacker->GetCharmerGUID().IsPlayer()); victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer); } } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 754bfbebf..8055d7417 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2312,6 +2312,32 @@ namespace Acore private: bool const _ascending; }; + + // Binary predicate for sorting Units based on current value of health + class HealthOrderPred + { + public: + HealthOrderPred(bool ascending = true) : _ascending(ascending) { } + + bool operator()(WorldObject const* objA, WorldObject const* objB) const + { + Unit const* a = objA->ToUnit(); + Unit const* b = objB->ToUnit(); + uint32 rA = a ? a->GetHealth() : 0; + uint32 rB = b ? b->GetHealth() : 0; + return _ascending ? rA < rB : rA > rB; + } + + bool operator() (Unit const* a, Unit const* b) const + { + uint32 rA = a ? a->GetHealth() : 0; + uint32 rB = b ? b->GetHealth() : 0; + return _ascending ? rA < rB : rA > rB; + } + + private: + bool const _ascending; + }; } class RedirectSpellEvent : public BasicEvent diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index ded80406b..2590926cc 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1895,7 +1895,10 @@ uint32 ObjectMgr::GetModelForShapeshift(ShapeshiftForm form, Player* player) con else customizationID = player->GetByteValue(PLAYER_BYTES, 0); // Use Skin Color - auto itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, player->getGender())); + // getGender() tracks the active display model; real gender lives in PLAYER_BYTES_3 + uint8 gender = player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER); + + auto itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), customizationID, gender)); if (itr != _playerShapeshiftModel.end()) return itr->second; // Explicit combination @@ -1903,7 +1906,7 @@ uint32 ObjectMgr::GetModelForShapeshift(ShapeshiftForm form, Player* player) con if (itr != _playerShapeshiftModel.end()) return itr->second; // Combination applied to both genders - itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, player->getGender())); + itr = _playerShapeshiftModel.find(std::make_tuple(form, player->getRace(), 255, gender)); if (itr != _playerShapeshiftModel.end()) return itr->second; // Default gender-dependent model @@ -3332,12 +3335,14 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.ContainerSlots = uint32(fields[26].Get()); uint8 statsCount = 0; - while (statsCount < MAX_ITEM_PROTO_STATS) + uint8 statsIterator = 0; + while (statsIterator < MAX_ITEM_PROTO_STATS) { - uint32 statType = uint32(fields[27 + statsCount * 2].Get()); - int32 statValue = fields[28 + statsCount * 2].Get(); - if (statType == 0) - break; + uint32 statType = uint32(fields[27 + statsIterator * 2].Get()); + int32 statValue = fields[28 + statsIterator * 2].Get(); + statsIterator++; + if (statValue == 0) + continue; itemTemplate.ItemStat[statsCount].ItemStatType = statType; itemTemplate.ItemStat[statsCount].ItemStatValue = statValue; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 8c51fef33..5d032dc79 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1992,7 +1992,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* return ERR_BATTLEGROUND_JOIN_RANGE_INDEX; // check for deserter debuff in case not arena queue - if (bgTemplate->GetBgTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground()) + if (bgTemplate->GetBgTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground(bgTemplate)) return ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS; // check if someone in party is using dungeon system diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 21daccde4..3a40fbc1a 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -31,6 +31,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "SocialMgr.h" #include "World.h" @@ -905,6 +906,13 @@ void Guild::BankMoveItemData::LogBankEvent(CharacterDatabaseTransaction trans, M void Guild::BankMoveItemData::LogAction(MoveItemData* pFrom) const { MoveItemData::LogAction(pFrom); + if (!pFrom->IsBank() && m_pPlayer->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(m_pPlayer->GetSession()->GetAccountId(), "GM {} (Account: {}) deposit item: {} (Entry: {} Count: {}) to guild bank named: {} (Guild ID: {})", + m_pPlayer->GetName(), m_pPlayer->GetSession()->GetAccountId(), + pFrom->GetItem()->GetTemplate()->Name1, pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(), + m_pGuild->GetName(), m_pGuild->GetId()); + } } Item* Guild::BankMoveItemData::_StoreItem(CharacterDatabaseTransaction trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const @@ -1714,6 +1722,12 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) CharacterDatabase.CommitTransaction(trans); + if (session->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(session->GetAccountId(), "GM {} (Account: {}) deposited {} to guild bank (Guild: {} GuildId: {})", + player->GetName(), session->GetAccountId(), amount, GetName(), GetId()); + } + std::string aux = Acore::Impl::ByteArrayToHexStr(reinterpret_cast(&m_bankMoney), 8, true); _BroadcastEvent(GE_BANK_MONEY_SET, ObjectGuid::Empty, aux.c_str()); @@ -1768,6 +1782,12 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool _LogBankEvent(trans, repair ? GUILD_BANK_LOG_REPAIR_MONEY : GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), player->GetGUID(), amount); CharacterDatabase.CommitTransaction(trans); + if (session->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(session->GetAccountId(), "GM {} (Account: {}) withdrew {} from guild bank (Guild: {} GuildId: {})", + player->GetName(), session->GetAccountId(), amount, GetName(), GetId()); + } + if (amount > 10 * GOLD) // sender_acc = 0 (guild has no account), sender_guid = Guild id, sender_name = Guild name CharacterDatabase.Execute("INSERT INTO log_money VALUES({}, {}, \"{}\", \"{}\", {}, \"{}\", {}, \"(guild, members: {}, new amount: {}, leader guid low: {}, withdrawer level: {})\", NOW(), {})", 0, GetId(), GetName(), session->GetRemoteAddress(), session->GetAccountId(), player->GetName(), amount, GetMemberCount(), GetTotalBankMoney(), GetLeaderGUID().GetCounter(), player->GetLevel(), 4); diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 5c0329186..78cf20cbd 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -24,6 +24,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "World.h" #include "WorldPacket.h" @@ -321,6 +322,13 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) created auction: {} (Item: {} Count: {}) Bid: {} Buyout: {}", + _player->GetName(), GetAccountId(), AH->Id, + item->GetTemplate()->Name1, item->GetCount(), bid, buyout); + } + GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); LOG_INFO("entities.player.auctionhouse", "AuctionHouse: Account: {} (IP: {}), Player [{}] (GUID: {}) created auction #{}: Item '{}' (Entry: {}) x{}, StartBid: {} copper, Buyout: {} copper, Deposit: {} copper", @@ -388,6 +396,13 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) created auction: {} (Item: {} Count: {}) Bid: {} Buyout: {}", + _player->GetName(), GetAccountId(), AH->Id, + newItem->GetTemplate()->Name1, newItem->GetCount(), bid, buyout); + } + GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); LOG_INFO("entities.player.auctionhouse", "AuctionHouse: Account: {} (IP: {}), Player [{}] (GUID: {}) created auction #{}: Item '{}' (Entry: {}) x{}, StartBid: {} copper, Buyout: {} copper, Deposit: {} copper", @@ -501,6 +516,13 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK, 0); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) bid on auction: {} (Item: {} Count: {}) Bid: {}", + player->GetName(), GetAccountId(), auction->Id, + auction->item_template, auction->itemCount, price); + } + LOG_INFO("entities.player.auctionhouse", "AuctionHouse: Account: {} (IP: {}), Player [{}] (GUID: {}) placed bid on auction #{}: Item (Entry: {}) x{}, Bid: {} copper, Owner: {} (GUID: {})", GetAccountId(), GetRemoteAddress(), player->GetName(), player->GetGUID().GetCounter(), auction->Id, auction->item_template, auction->itemCount, price, auction->owner.GetCounter(), auction->owner.GetCounter()); @@ -528,6 +550,13 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) bought out auction: {} (Item: {} Count: {}) Buyout: {}", + player->GetName(), GetAccountId(), auction->Id, + auction->item_template, auction->itemCount, auction->buyout); + } + LOG_INFO("entities.player.auctionhouse", "AuctionHouse: Account: {} (IP: {}), Player [{}] (GUID: {}) bought out auction #{}: Item (Entry: {}) x{}, Buyout: {} copper, Owner: {} (GUID: {})", GetAccountId(), GetRemoteAddress(), player->GetName(), player->GetGUID().GetCounter(), auction->Id, auction->item_template, auction->itemCount, auction->buyout, auction->owner.GetCounter(), auction->owner.GetCounter()); diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 499bae1e6..f9cbfac32 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -161,7 +161,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) { err = ERR_LFG_CANT_USE_BATTLEGROUND; } - else if (!_player->CanJoinToBattleground()) // has deserter debuff + else if (!_player->CanJoinToBattleground(bg)) // has deserter debuff { err = ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS; } @@ -473,7 +473,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData) if (action == 1 && ginfo.ArenaType == 0) { // can't join with deserter, check it here right before joining to be sure - if (!_player->CanJoinToBattleground()) + if (!_player->CanJoinToBattleground(bg)) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index a7dcfee95..719bb4be1 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -17,6 +17,7 @@ #include "AccountMgr.h" #include "AreaDefines.h" +#include "RBAC.h" #include "ArenaTeamMgr.h" #include "AuctionHouseMgr.h" #include "Battleground.h" @@ -275,7 +276,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) >> createInfo->FacialHair >> createInfo->OutfitId; - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK)) { if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED)) { @@ -319,7 +320,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) return; } - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK)) { uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); if ((1 << (createInfo->Race - 1)) & raceMaskDisabled) @@ -327,7 +328,10 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) SendCharCreate(CHAR_CREATE_DISABLED); return; } + } + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK)) + { uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK); if ((1 << (createInfo->Class - 1)) & classMaskDisabled) { @@ -348,13 +352,16 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) uint8 res = ObjectMgr::CheckPlayerName(createInfo->Name, true); if (res != CHAR_NAME_SUCCESS) { - SendCharCreate(ResponseCodes(res)); - return; + if (res != CHAR_NAME_RESERVED || !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME)) + { + SendCharCreate(ResponseCodes(res)); + return; + } } // speedup check for heroic class disabled case uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); - if (heroic_free_slots == 0 && AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) + if (heroic_free_slots == 0 && !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEATH_KNIGHT) && createInfo->Class == CLASS_DEATH_KNIGHT) { SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT); return; @@ -362,7 +369,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) // speedup check for heroic class disabled case uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEATH_KNIGHT) && createInfo->Class == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { SendCharCreate(CHAR_CREATE_LEVEL_REQUIREMENT); return; @@ -417,7 +424,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) } } - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); std::function finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result) @@ -430,9 +437,9 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) bool haveSameRace = false; uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); bool hasHeroicReqLevel = (heroicReqLevel == 0); - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); - bool checkDeathKnightReqs = AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT; + bool checkDeathKnightReqs = !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEATH_KNIGHT) && createInfo->Class == CLASS_DEATH_KNIGHT; if (result) { @@ -1360,8 +1367,11 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData) uint8 res = ObjectMgr::CheckPlayerName(renameInfo->Name, true); if (res != CHAR_NAME_SUCCESS) { - SendCharRename(ResponseCodes(res), renameInfo.get()); - return; + if (res != CHAR_NAME_RESERVED || !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME)) + { + SendCharRename(ResponseCodes(res), renameInfo.get()); + return; + } } // Ensure that the character belongs to the current account, that rename at login is enabled @@ -1700,8 +1710,11 @@ void WorldSession::HandleCharCustomizeCallback(std::shared_ptr(ObjectMgr::CheckPlayerName(customizeInfo->Name, true)); if (res != CHAR_NAME_SUCCESS) { - SendCharCustomize(res, customizeInfo.get()); - return; + if (res != CHAR_NAME_RESERVED || !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME)) + { + SendCharCustomize(res, customizeInfo.get()); + return; + } } // character with this name already exist @@ -2079,7 +2092,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrgetIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); if ((1 << (factionChangeInfo->Race - 1)) & raceMaskDisabled) @@ -2099,8 +2112,11 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr(ObjectMgr::CheckPlayerName(factionChangeInfo->Name, true)); if (res != CHAR_NAME_SUCCESS) { - SendCharFactionChange(res, factionChangeInfo.get()); - return; + if (res != CHAR_NAME_RESERVED || !HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME)) + { + SendCharFactionChange(res, factionChangeInfo.get()); + return; + } } // character with this name already exist @@ -2316,7 +2332,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrDeleteMember(factionChangeInfo->Guid, false, false, true); } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) + if (!HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND)) { // Delete Friend List stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID); diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 23417e1aa..2cce9521b 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -17,6 +17,7 @@ #include "AccountMgr.h" #include "CellImpl.h" +#include "RBAC.h" #include "ChannelMgr.h" #include "Chat.h" #include "ChatPackets.h" @@ -112,7 +113,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } // pussywizard: chatting on most chat types requires 2 hours played to prevent spam/abuse - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ)) { switch (type) { @@ -385,8 +386,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } Player* receiver = ObjectAccessor::FindPlayerByName(to, false); - bool senderIsPlayer = AccountMgr::IsPlayerAccount(GetSecurity()); - bool receiverIsPlayer = AccountMgr::IsPlayerAccount(receiver ? receiver->GetSession()->GetSecurity() : SEC_PLAYER); + bool senderIsPlayer = !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT); + bool receiverIsPlayer = receiver ? !receiver->GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT) : true; if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) && receiver != sender && receiver && !receiver->IsGameMaster()) { @@ -394,7 +395,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } - if (!receiver || (senderIsPlayer && !receiverIsPlayer && !receiver->isAcceptWhispers() && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) + if (!receiver || (lang != LANG_ADDON && !receiver->isAcceptWhispers() && receiver->GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS) && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) { SendPlayerNotFoundNotice(to); return; @@ -407,7 +408,6 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } - // pussywizard: optimization if (GetPlayer()->HasAura(1852) && !receiver->IsGameMaster()) { ChatHandler(this).SendNotification(LANG_GM_SILENCE, GetPlayer()->GetName()); @@ -415,7 +415,9 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to - if (!senderIsPlayer && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID())) + // We also do that if a player is under the required level for whispers. + if (receiver->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) || + (HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS) && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID()))) sender->AddWhisperWhiteList(receiver->GetGUID()); GetPlayer()->Whisper(msg, Language(lang), receiver); @@ -557,7 +559,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) break; case CHAT_MSG_CHANNEL: { - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ)) { if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) { diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 387a69238..b7083c0fa 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -17,6 +17,7 @@ #include "AccountMgr.h" #include "Chat.h" +#include "RBAC.h" #include "CharacterCache.h" #include "DBCStores.h" #include "DatabaseEnv.h" @@ -38,9 +39,9 @@ bool WorldSession::CanOpenMailBox(ObjectGuid guid) { if (guid == _player->GetGUID()) { - if (_player->GetSession()->GetSecurity() < SEC_MODERATOR) + if (!HasPermission(rbac::RBAC_PERM_COMMAND_MAILBOX)) { - LOG_ERROR("network.opcode", "{} attempt open mailbox in cheating way.", _player->GetName()); + LOG_WARN("cheat", "{} attempted to open mailbox by using a cheat.", _player->GetName()); return false; } } @@ -213,7 +214,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(receiverGuid); - if (/*!accountBound*/ GetAccountId() != rc_account && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeamId() != rc_teamId && AccountMgr::IsPlayerAccount(GetSecurity())) + if (/*!accountBound*/ GetAccountId() != rc_account && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeamId() != rc_teamId && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; @@ -286,6 +287,25 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) player->SendMailResult(0, MAIL_SEND, MAIL_OK); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + if (items_count > 0) + { + for (uint8 i = 0; i < items_count; ++i) + { + Item* item = items[i]; + LOG_GM(GetAccountId(), "GM {} (Account: {}) sent mail to {} (Account: {}) with item: {} (Entry: {} Count: {})", + player->GetName(), GetAccountId(), receiver, rc_account, + item->GetTemplate()->Name1, item->GetEntry(), item->GetCount()); + } + } + if (money > 0) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) sent mail to {} (Account: {}) with money: {}", + player->GetName(), GetAccountId(), receiver, rc_account, money); + } + } + player->ModifyMoney(-int32(reqmoney)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); @@ -585,6 +605,12 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) it->SetState(ITEM_UNCHANGED); // need to set this state, otherwise item cannot be removed later, if neccessary player->MoveItemToInventory(dest, it, true); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) took mail item: {} (Entry: {} Count: {}) from mailbox", + player->GetName(), GetAccountId(), it->GetTemplate()->Name1, it->GetEntry(), count); + } + player->SaveInventoryAndGoldToDB(trans); player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); @@ -620,6 +646,12 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) return; } + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(GetAccountId(), "GM {} (Account: {}) took mail money: {} from mailbox", + player->GetName(), GetAccountId(), m->money); + } + m->money = 0; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 56047089f..30886a778 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -17,6 +17,7 @@ #include "AccountMgr.h" #include "BattlefieldMgr.h" +#include "RBAC.h" #include "Battleground.h" #include "BattlegroundMgr.h" #include "CharacterPackets.h" @@ -283,8 +284,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) levelMax = STRONG_MAX_LEVEL; uint32 team = _player->GetTeamId(); - uint32 security = GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); uint32 displaycount = 0; @@ -294,20 +293,13 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) for (auto const& target : sWhoListCacheMgr->GetWhoList()) { - if (AccountMgr::IsPlayerAccount(security)) - { - // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST - if (target.GetTeamId() != team && !allowTwoSideWhoList) - { - continue; - } + // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST + if (target.GetTeamId() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST)) + continue; - // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST - if (target.GetSecurity() > AccountTypes(gmLevelInWhoList)) - { - continue; - } - } + // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST + if (!HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && target.GetSecurity() > AccountTypes(gmLevelInWhoList)) + continue; // check if target is globally visible for player if ((_player->GetGUID() != target.GetGuid() && !target.IsVisible()) && @@ -429,7 +421,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ if (ObjectGuid lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); - bool instantLogout = ((GetSecurity() >= 0 && uint32(GetSecurity()) >= sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT)) + bool instantLogout = (HasPermission(rbac::RBAC_PERM_INSTANT_LOGOUT) || (GetPlayer()->HasPlayerFlag(PLAYER_FLAGS_RESTING) && !GetPlayer()->IsInCombat())) || GetPlayer()->IsInFlight(); bool preventAfkSanctuaryLogout = sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 1 @@ -1010,7 +1002,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recv_data) WorldPacket data(SMSG_INSPECT_TALENT, guid_size + 4 + talent_points); data << player->GetPackGUID(); - if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->IsGameMaster()) + if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->CanBeGameMaster()) { player->BuildPlayerTalentsInfoData(&data); } @@ -1081,7 +1073,7 @@ void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data) LOG_DEBUG("network", "CMSG_WORLD_TELEPORT: Player = {}, Time = {}, map = {}, x = {}, y = {}, z = {}, o = {}", GetPlayer()->GetName(), time, mapid, PositionX, PositionY, PositionZ, Orientation); - if (AccountMgr::IsAdminAccount(GetSecurity())) + if (HasPermission(rbac::RBAC_PERM_OPCODE_WORLD_TELEPORT)) GetPlayer()->TeleportTo(mapid, PositionX, PositionY, PositionZ, Orientation); else ChatHandler(this).SendNotification(LANG_PERMISSION_DENIED); @@ -1093,7 +1085,7 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) std::string charname; recv_data >> charname; - if (!AccountMgr::IsAdminAccount(GetSecurity())) + if (!HasPermission(rbac::RBAC_PERM_OPCODE_WHOIS)) { ChatHandler(this).SendNotification(LANG_PERMISSION_DENIED); return; diff --git a/src/server/game/Handlers/Socialhandler.cpp b/src/server/game/Handlers/Socialhandler.cpp index 6fccfa1d3..23038746e 100644 --- a/src/server/game/Handlers/Socialhandler.cpp +++ b/src/server/game/Handlers/Socialhandler.cpp @@ -17,6 +17,7 @@ #include "AccountMgr.h" #include "Language.h" +#include "RBAC.h" #include "Log.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -57,13 +58,13 @@ void WorldSession::HandleAddFriendOpcode(WorldPacket& recv_data) TeamId teamId = Player::TeamIdForRace(playerData->Race); FriendsResult friendResult = FRIEND_NOT_FOUND; - if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND)|| AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realm.Id.Realm))) + if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realm.Id.Realm))) { if (friendGuid) { if (friendGuid == GetPlayer()->GetGUID()) friendResult = FRIEND_SELF; - else if (GetPlayer()->GetTeamId() != teamId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && AccountMgr::IsPlayerAccount(GetSecurity())) + else if (GetPlayer()->GetTeamId() != teamId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND)) friendResult = FRIEND_ENEMY; else if (GetPlayer()->GetSocial()->HasFriend(friendGuid)) friendResult = FRIEND_ALREADY; diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 8fbe3018e..8266d13d1 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -22,6 +22,7 @@ #include "ObjectAccessor.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "SocialMgr.h" #include "Spell.h" @@ -504,6 +505,35 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) trader->ModifyMoney(-int32(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); + if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (myItems[i]) + LOG_GM(GetAccountId(), "GM {} (Account: {}) traded item: {} (Entry: {} Count: {}) to {}", + _player->GetName(), GetAccountId(), + myItems[i]->GetTemplate()->Name1, myItems[i]->GetEntry(), myItems[i]->GetCount(), + trader->GetName()); + } + if (my_trade->GetMoney() > 0) + LOG_GM(GetAccountId(), "GM {} (Account: {}) traded money: {} to {}", + _player->GetName(), GetAccountId(), my_trade->GetMoney(), trader->GetName()); + } + if (trader->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (hisItems[i]) + LOG_GM(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) traded item: {} (Entry: {} Count: {}) to {}", + trader->GetName(), trader->GetSession()->GetAccountId(), + hisItems[i]->GetTemplate()->Name1, hisItems[i]->GetEntry(), hisItems[i]->GetCount(), + _player->GetName()); + } + if (his_trade->GetMoney() > 0) + LOG_GM(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) traded money: {} to {}", + trader->GetName(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName()); + } + // log completed trade LOG_INFO("entities.player.trade", "Trade: Account: {} (IP: {}), Player [{}] ({}) traded with Player [{}] ({}): gave {} copper, received {} copper, gave item(s) [{}], received item(s) [{}]", GetAccountId(), GetRemoteAddress(), _player->GetName(), _player->GetGUID().GetCounter(), @@ -671,7 +701,9 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeamId() != _player->GetTeamId()) + if (pOther->GetTeamId() != _player->GetTeamId() && + !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && + !GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_ALLOW_TWO_SIDE_TRADE)) { info.Status = TRADE_STATUS_WRONG_FACTION; SendTradeStatus(info); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 94b367e61..f4dec4454 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -28,6 +28,7 @@ #include "Opcodes.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "Spell.h" #include "WorldSession.h" @@ -387,6 +388,11 @@ void InstanceScript::SetSummoner(Creature* creature) summoner->AI()->JustSummoned(creature); } +bool InstanceScript::_SkipCheckRequiredBosses(Player const* player /*= nullptr*/) const +{ + return player && player->GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES); +} + bool InstanceScript::SetBossState(uint32 id, EncounterState state) { if (id < bosses.size()) diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index ba05588ee..8b9c1e677 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -264,6 +264,8 @@ public: // Checks boss requirements (one boss required to kill other) virtual bool CheckRequiredBosses(uint32 /*bossId*/, Player const* /*player*/ = nullptr) const { return true; } + bool _SkipCheckRequiredBosses(Player const* player = nullptr) const; + void SetCompletedEncountersMask(uint32 newMask, bool save); // Returns completed encounters mask for packets diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 8ecc58b47..de55d37cd 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -112,7 +112,10 @@ enum AcoreStrings LANG_PVPSTATS = 80, LANG_PVPSTATS_DISABLED = 81, LANG_GENERIC_TWO_CURLIES_WITH_COLON = 82, - // Free 83 - 86 + LANG_RBAC_HELP_ACC_LIST = 83, + LANG_RBAC_HELP_ACC_GRANT = 84, + LANG_RBAC_HELP_ACC_DENY = 85, + LANG_RBAC_HELP_ACC_REVOKE = 86, LANG_UNKNOWN_ERROR = 87, LANG_2FA_COMMANDS_NOT_SETUP = 88, diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 135845572..f1cf4e74a 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -41,6 +41,7 @@ #include "PacketUtilities.h" #include "Pet.h" #include "Player.h" +#include "Realm.h" #include "QueryHolder.h" #include "ScriptMgr.h" #include "SocialMgr.h" @@ -115,6 +116,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, s _security(sec), _skipQueue(skipQueue), _accountId(id), + _RBACData(nullptr), _accountName(std::move(name)), _accountFlags(accountFlags), m_expansion(expansion), @@ -176,6 +178,8 @@ WorldSession::~WorldSession() m_Socket = nullptr; } + delete _RBACData; + ///- empty incoming packet queue WorldPacket* packet = nullptr; while (_recvQueue.next(packet)) @@ -373,7 +377,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) ///- Before we process anything: /// If necessary, kick the player because the client didn't send anything for too long /// (or they've been idling in character select) - if (sWorld->getBoolConfig(CONFIG_CLOSE_IDLE_CONNECTIONS) && IsConnectionIdle() && m_Socket) + if (m_Socket && IsConnectionIdle() && !HasPermission(rbac::RBAC_PERM_IGNORE_IDLE_CONNECTION)) m_Socket->CloseSocket(); if (updater.ProcessUnsafe()) @@ -1557,3 +1561,54 @@ LockedQueue& WorldSession::GetPacketQueue() { return _recvQueue; } + +void WorldSession::LoadPermissions() +{ + uint32 id = GetAccountId(); + uint8 secLevel = GetSecurity(); + + LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: {}, Name: {}, realmId: {}, secLevel: {}]", + id, _accountName, realm.Id.Realm, secLevel); + + _RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel); + _RBACData->LoadFromDB(); +} + +QueryCallback WorldSession::LoadPermissionsAsync() +{ + uint32 id = GetAccountId(); + uint8 secLevel = GetSecurity(); + + LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: {}, Name: {}, realmId: {}, secLevel: {}]", + id, _accountName, realm.Id.Realm, secLevel); + + _RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel); + return _RBACData->LoadFromDBAsync(); +} + +bool WorldSession::HasPermission(uint32 permission) +{ + if (!_RBACData) + LoadPermissions(); + + bool hasPermission = _RBACData->HasPermission(permission); + LOG_DEBUG("rbac", "WorldSession::HasPermission [AccountId: {}, Name: {}, realmId: {}]", + _RBACData->GetId(), _RBACData->GetName(), realm.Id.Realm); + + return hasPermission; +} + +void WorldSession::InvalidateRBACData() +{ + LOG_DEBUG("rbac", "WorldSession::InvalidateRBACData [AccountId: {}, Name: {}, realmId: {}]", + _RBACData->GetId(), _RBACData->GetName(), realm.Id.Realm); + delete _RBACData; + _RBACData = nullptr; +} + +void WorldSession::InitRBACDataForTest() +{ + delete _RBACData; + _RBACData = new rbac::RBACData(_accountId, _accountName, realm.Id.Realm, _security); + _RBACData->LoadFromDBCallback(nullptr); +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 08391493f..65da35370 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -459,6 +459,16 @@ public: AccountTypes GetSecurity() const { return _security; } bool CanSkipQueue() const { return _skipQueue; } + + // RBAC + rbac::RBACData* GetRBACData() const { return _RBACData; } + bool HasPermission(uint32 permissionId); + void LoadPermissions(); + QueryCallback LoadPermissionsAsync(); + void InvalidateRBACData(); + + /// For unit testing - initializes RBAC data without database access + void InitRBACDataForTest(); uint32 GetAccountId() const { return _accountId; } Player* GetPlayer() const { return _player; } std::string const& GetPlayerName() const; @@ -1252,6 +1262,7 @@ private: AccountTypes _security; bool _skipQueue; uint32 _accountId; + rbac::RBACData* _RBACData; std::string _accountName; uint32 _accountFlags; uint8 m_expansion; diff --git a/src/server/game/Server/WorldSessionMgr.cpp b/src/server/game/Server/WorldSessionMgr.cpp index 91256db9b..a901914e3 100644 --- a/src/server/game/Server/WorldSessionMgr.cpp +++ b/src/server/game/Server/WorldSessionMgr.cpp @@ -17,6 +17,7 @@ #include "Chat.h" #include "ChatPackets.h" +#include "RBAC.h" #include "GameTime.h" #include "Metric.h" #include "Player.h" @@ -328,7 +329,7 @@ void WorldSessionMgr::AddSession_(WorldSession* session) // don't count this session when checking player limit --Sessions; - if (pLimit > 0 && Sessions >= pLimit && AccountMgr::IsPlayerAccount(session->GetSecurity()) && !session->CanSkipQueue() && !HasRecentlyDisconnected(session)) + if (pLimit > 0 && Sessions >= pLimit && !session->HasPermission(rbac::RBAC_PERM_SKIP_QUEUE) && !session->CanSkipQueue() && !HasRecentlyDisconnected(session)) { AddQueuedPlayer(session); UpdateMaxSessionCounters(); @@ -395,7 +396,7 @@ void WorldSessionMgr::SendGlobalGMMessage(WorldPacket const* packet, WorldSessio itr->second->GetPlayer() && itr->second->GetPlayer()->IsInWorld() && itr->second != self && - !AccountMgr::IsPlayerAccount(itr->second->GetSecurity()) && + itr->second->HasPermission(rbac::RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE) && (teamId == TEAM_NEUTRAL || itr->second->GetPlayer()->GetTeamId() == teamId)) { itr->second->SendPacket(packet); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index cf809ba0a..e4ca47d10 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -31,6 +31,7 @@ #include "World.h" #include "WorldSession.h" #include "WorldSessionMgr.h" +#include "RBAC.h" #include "zlib.h" #include @@ -763,7 +764,7 @@ bool WorldSocket::HandlePing(WorldPacket& recvPacket) { std::unique_lock sessionGuard(_worldSessionLock); - if (_worldSession && AccountMgr::IsPlayerAccount(_worldSession->GetSecurity())) + if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING)) { LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})", _worldSession->GetPlayerInfo(), GetRemoteIpAddress().to_string()); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 1113d6c90..b36c34d45 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -42,6 +42,7 @@ #include "OutdoorPvPMgr.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "SharedDefines.h" @@ -2900,6 +2901,14 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) // add new enchanting if equipped item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, true); + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(p_caster->GetSession()->GetAccountId(), "GM {} (Account: {}) enchanting(perm): {} (SpellID: {} EncID: {}) on {}'s item: {} (Entry: {})", + p_caster->GetName(), p_caster->GetSession()->GetAccountId(), + m_spellInfo->SpellName[0], m_spellInfo->Id, enchant_id, + item_owner->GetName(), itemTarget->GetTemplate()->Name1, itemTarget->GetEntry()); + } + item_owner->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(item_owner); } @@ -2947,6 +2956,15 @@ void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex) if (!item_owner) return; + Player* p_caster = m_caster->ToPlayer(); + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(p_caster->GetSession()->GetAccountId(), "GM {} (Account: {}) enchanting(prismatic): {} (SpellID: {} EncID: {}) on {}'s item: {} (Entry: {})", + p_caster->GetName(), p_caster->GetSession()->GetAccountId(), + m_spellInfo->SpellName[0], m_spellInfo->Id, enchant_id, + item_owner->GetName(), itemTarget->GetTemplate()->Name1, itemTarget->GetEntry()); + } + // remove old enchanting before applying new if equipped item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, false); @@ -3096,6 +3114,14 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) // add new enchanting if equipped item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true); + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) + { + LOG_GM(p_caster->GetSession()->GetAccountId(), "GM {} (Account: {}) enchanting(temp): {} (SpellID: {} EncID: {}) on {}'s item: {} (Entry: {})", + p_caster->GetName(), p_caster->GetSession()->GetAccountId(), + m_spellInfo->SpellName[0], m_spellInfo->Id, enchant_id, + item_owner->GetName(), itemTarget->GetTemplate()->Name1, itemTarget->GetEntry()); + } + item_owner->RemoveTradeableItem(itemTarget); itemTarget->ClearSoulboundTradeable(item_owner); } diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 2b819330e..03b9107fe 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -5075,7 +5075,6 @@ void SpellMgr::LoadSpellInfoCorrections() // Eye of Acherus Flight (Boost) ApplySpellFix({ 51923 }, [](SpellInfo* spellInfo) { - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED; spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); }); @@ -5190,6 +5189,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->ProcCharges = 0; }); + // 54933 Hyldnir Harpoon + ApplySpellFix({ 54933 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].BasePoints = 1; + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index af70ec147..011c8ec19 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3157,6 +3157,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes() // Exceptions case 44801: // Spectral Invisibility (Kalecgos, SWP) case 46021: // Spectral Realm (SWP) + case 52951: // Chapel Invisibility (DK starting zone) break; default: spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST; diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index dc6c60681..b6eb947ac 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -115,6 +115,7 @@ public: [[nodiscard]] virtual std::string const& GetRealmName() const = 0; virtual void SetRealmName(std::string name) = 0; virtual SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) = 0; + virtual void ReloadRBAC() = 0; }; #endif //AZEROTHCORE_IWORLD_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e54cd13b1..f87323153 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -470,6 +470,9 @@ void World::SetInitialWorldSettings() LOG_INFO("server.loading", ">> Localization Strings loaded in {} ms", GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); + LOG_INFO("server.loading", "Loading Account Roles and Permissions..."); + sAccountMgr->LoadRBAC(); + LOG_INFO("server.loading", "Loading Page Texts..."); sObjectMgr->LoadPageTexts(); @@ -1746,6 +1749,16 @@ void World::ResetEventSeasonalQuests(uint16 event_id) itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id); } +void World::ReloadRBAC() +{ + // Passive reload, we mark the data as invalidated and next time a permission is checked it will be reloaded + LOG_INFO("rbac", "World::ReloadRBAC()"); + WorldSessionMgr::SessionMap const& sessionMap = sWorldSessionMgr->GetAllSessions(); + for (WorldSessionMgr::SessionMap::const_iterator itr = sessionMap.begin(); itr != sessionMap.end(); ++itr) + if (WorldSession* session = itr->second) + session->InvalidateRBACData(); +} + void World::ResetRandomBG() { LOG_DEBUG("server.worldserver", "Random BG status reset for all characters."); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 470ceca0c..24eb42afa 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -238,6 +238,7 @@ public: [[nodiscard]] uint32 GetCleaningFlags() const override { return _cleaningFlags; } void SetCleaningFlags(uint32 flags) override { _cleaningFlags = flags; } void ResetEventSeasonalQuests(uint16 event_id) override; + void ReloadRBAC() override; [[nodiscard]] std::string const& GetRealmName() const override { return _realmName; } // pussywizard void SetRealmName(std::string name) override { _realmName = name; } // pussywizard diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index ad9f1f66e..9c37eff54 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -23,6 +23,7 @@ #include "CryptoGenerics.h" #include "IPLocation.h" #include "Player.h" +#include "RBAC.h" #include "Realm.h" #include "ScriptMgr.h" #include "SecretMgr.h" @@ -45,42 +46,42 @@ public: { static ChatCommandTable accountSetCommandTable = { - { "addon", HandleAccountSetAddonCommand, SEC_GAMEMASTER, Console::Yes }, - { "gmlevel", HandleAccountSetGmLevelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "password", HandleAccountSetPasswordCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "2fa", HandleAccountSet2FACommand, SEC_PLAYER, Console::Yes }, - { "email", HandleAccountSetEmailCommand, SEC_ADMINISTRATOR, Console::Yes } + { "addon", HandleAccountSetAddonCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON, Console::Yes }, + { "gmlevel", HandleAccountSetGmLevelCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_SET_SECLEVEL, Console::Yes }, + { "password", HandleAccountSetPasswordCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD, Console::Yes }, + { "2fa", HandleAccountSet2FACommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_SET, Console::Yes }, + { "email", HandleAccountSetEmailCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL, Console::Yes } }; static ChatCommandTable accountLockCommandTable { - { "country", HandleAccountLockCountryCommand, SEC_PLAYER, Console::Yes }, - { "ip", HandleAccountLockIpCommand, SEC_PLAYER, Console::Yes } + { "country", HandleAccountLockCountryCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY, Console::Yes }, + { "ip", HandleAccountLockIpCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP, Console::Yes } }; static ChatCommandTable account2faCommandTable { - { "setup", HandleAccount2FASetupCommand, SEC_PLAYER, Console::No }, - { "remove", HandleAccount2FARemoveCommand, SEC_PLAYER, Console::No } + { "setup", HandleAccount2FASetupCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT, Console::No }, + { "remove", HandleAccount2FARemoveCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT, Console::No } }; static ChatCommandTable accountRemoveCommandTable { - { "country", HandleAccountRemoveLockCountryCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "country", HandleAccountRemoveLockCountryCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY, Console::Yes }, }; static ChatCommandTable accountCommandTable = { { "2fa", account2faCommandTable }, - { "addon", HandleAccountAddonCommand, SEC_MODERATOR, Console::No }, - { "create", HandleAccountCreateCommand, SEC_CONSOLE, Console::Yes }, - { "delete", HandleAccountDeleteCommand, SEC_CONSOLE, Console::Yes }, - { "onlinelist", HandleAccountOnlineListCommand, SEC_CONSOLE, Console::Yes }, + { "addon", HandleAccountAddonCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_ADDON, Console::No }, + { "create", HandleAccountCreateCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_CREATE, Console::Yes }, + { "delete", HandleAccountDeleteCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_DELETE, Console::Yes }, + { "onlinelist", HandleAccountOnlineListCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST, Console::Yes }, { "lock", accountLockCommandTable }, { "set", accountSetCommandTable }, - { "password", HandleAccountPasswordCommand, SEC_PLAYER, Console::No }, + { "password", HandleAccountPasswordCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT_PASSWORD, Console::No }, { "remove", accountRemoveCommandTable }, - { "", HandleAccountCommand, SEC_PLAYER, Console::No } + { "", HandleAccountCommand, rbac::RBAC_PERM_COMMAND_ACCOUNT, Console::No } }; static ChatCommandTable commandTable = @@ -279,7 +280,7 @@ public: // if email is not specified, use empty string std::string emailStr = email ? email : ""; - AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password), emailStr); + AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), emailStr); switch (result) { case AOR_OK: @@ -658,6 +659,16 @@ public: { AccountTypes gmLevel = handler->GetSession()->GetSecurity(); handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmLevel)); + + if (handler->GetSession()->HasPermission(rbac::RBAC_PERM_MAY_CHECK_OWN_EMAIL)) + { + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID); + stmt->SetData(0, handler->GetSession()->GetAccountId()); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + handler->PSendSysMessage(LANG_COMMAND_EMAIL_OUTPUT, (*result)[0].Get()); + } + return true; } diff --git a/src/server/scripts/Commands/cs_achievement.cpp b/src/server/scripts/Commands/cs_achievement.cpp index 8557f46ae..37963f8aa 100644 --- a/src/server/scripts/Commands/cs_achievement.cpp +++ b/src/server/scripts/Commands/cs_achievement.cpp @@ -20,6 +20,7 @@ #include "CommandScript.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -32,8 +33,8 @@ public: { static ChatCommandTable achievementCommandTable = { - { "add", HandleAchievementAddCommand, SEC_GAMEMASTER, Console::Yes }, - { "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::Yes } + { "add", HandleAchievementAddCommand, rbac::RBAC_PERM_COMMAND_ACHIEVEMENT_ADD, Console::Yes }, + { "checkall", HandleAchievementCheckAllCommand, rbac::RBAC_PERM_COMMAND_ACHIEVEMENT_CHECKALL, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_arena.cpp b/src/server/scripts/Commands/cs_arena.cpp index 4adb0f736..a2a8f92cf 100644 --- a/src/server/scripts/Commands/cs_arena.cpp +++ b/src/server/scripts/Commands/cs_arena.cpp @@ -15,12 +15,13 @@ * with this program. If not, see . */ -#include "ArenaTeamMgr.h" #include "ArenaSeasonMgr.h" #include "ArenaTeamFilter.h" +#include "ArenaTeamMgr.h" #include "Chat.h" #include "CommandScript.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -33,25 +34,25 @@ public: { static ChatCommandTable arenaSeasonSetCommandTable = { - { "state", HandleArenaSeasonSetStateCommand, SEC_ADMINISTRATOR, Console::Yes } + { "state", HandleArenaSeasonSetStateCommand, rbac::RBAC_PERM_COMMAND_ARENA_SEASON, Console::Yes } }; static ChatCommandTable arenaSeasonCommandTable = { - { "reward", HandleArenaSeasonRewardCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "deleteteams", HandleArenaSeasonDeleteTeamsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "start", HandleArenaSeasonStartCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "reward", HandleArenaSeasonRewardCommand, rbac::RBAC_PERM_COMMAND_ARENA_SEASON_REWARD, Console::Yes }, + { "deleteteams", HandleArenaSeasonDeleteTeamsCommand, rbac::RBAC_PERM_COMMAND_ARENA_SEASON_DELETETEAMS, Console::Yes }, + { "start", HandleArenaSeasonStartCommand, rbac::RBAC_PERM_COMMAND_ARENA_SEASON_START, Console::Yes }, { "set", arenaSeasonSetCommandTable } }; static ChatCommandTable arenaCommandTable = { - { "create", HandleArenaCreateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "disband", HandleArenaDisbandCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "rename", HandleArenaRenameCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "captain", HandleArenaCaptainCommand, SEC_ADMINISTRATOR, Console::No }, - { "info", HandleArenaInfoCommand, SEC_GAMEMASTER, Console::Yes }, - { "lookup", HandleArenaLookupCommand, SEC_GAMEMASTER, Console::Yes }, + { "create", HandleArenaCreateCommand, rbac::RBAC_PERM_COMMAND_ARENA_CREATE, Console::Yes }, + { "disband", HandleArenaDisbandCommand, rbac::RBAC_PERM_COMMAND_ARENA_DISBAND, Console::Yes }, + { "rename", HandleArenaRenameCommand, rbac::RBAC_PERM_COMMAND_ARENA_RENAME, Console::Yes }, + { "captain", HandleArenaCaptainCommand, rbac::RBAC_PERM_COMMAND_ARENA_CAPTAIN, Console::No }, + { "info", HandleArenaInfoCommand, rbac::RBAC_PERM_COMMAND_ARENA_INFO, Console::Yes }, + { "lookup", HandleArenaLookupCommand, rbac::RBAC_PERM_COMMAND_ARENA_LOOKUP, Console::Yes }, { "season", arenaSeasonCommandTable } }; diff --git a/src/server/scripts/Commands/cs_bag.cpp b/src/server/scripts/Commands/cs_bag.cpp index fd365b875..a0567e49c 100644 --- a/src/server/scripts/Commands/cs_bag.cpp +++ b/src/server/scripts/Commands/cs_bag.cpp @@ -19,6 +19,7 @@ #include "CommandScript.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" constexpr std::array itemQualityToString = { @@ -43,7 +44,7 @@ public: { static ChatCommandTable commandTable = { - { "bags clear", HandleBagsClearCommand, SEC_GAMEMASTER, Console::No }, + { "bags clear", HandleBagsClearCommand, rbac::RBAC_PERM_COMMAND_ADDITEM, Console::No }, }; return commandTable; diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index 466364be8..539b60e06 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -25,6 +25,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" /// Ban function modes enum BanMode @@ -49,32 +50,32 @@ public: { static ChatCommandTable unbanCommandTable = { - { "account", HandleUnBanAccountCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "character", HandleUnBanCharacterCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "playeraccount", HandleUnBanAccountByCharCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "ip", HandleUnBanIPCommand, SEC_ADMINISTRATOR, Console::Yes } + { "account", HandleUnBanAccountCommand, rbac::RBAC_PERM_COMMAND_UNBAN_ACCOUNT, Console::Yes }, + { "character", HandleUnBanCharacterCommand, rbac::RBAC_PERM_COMMAND_UNBAN_CHARACTER, Console::Yes }, + { "playeraccount", HandleUnBanAccountByCharCommand, rbac::RBAC_PERM_COMMAND_UNBAN_PLAYERACCOUNT, Console::Yes }, + { "ip", HandleUnBanIPCommand, rbac::RBAC_PERM_COMMAND_UNBAN_IP, Console::Yes } }; static ChatCommandTable banlistCommandTable = { - { "account", HandleBanListAccountCommand, SEC_GAMEMASTER, Console::Yes }, - { "character", HandleBanListCharacterCommand, SEC_GAMEMASTER, Console::Yes }, - { "ip", HandleBanListIPCommand, SEC_GAMEMASTER, Console::Yes } + { "account", HandleBanListAccountCommand, rbac::RBAC_PERM_COMMAND_BANLIST_ACCOUNT, Console::Yes }, + { "character", HandleBanListCharacterCommand, rbac::RBAC_PERM_COMMAND_BANLIST_CHARACTER, Console::Yes }, + { "ip", HandleBanListIPCommand, rbac::RBAC_PERM_COMMAND_BANLIST_IP, Console::Yes } }; static ChatCommandTable baninfoCommandTable = { - { "account", HandleBanInfoAccountCommand, SEC_GAMEMASTER, Console::Yes }, - { "character", HandleBanInfoCharacterCommand, SEC_GAMEMASTER, Console::Yes }, - { "ip", HandleBanInfoIPCommand, SEC_GAMEMASTER, Console::Yes } + { "account", HandleBanInfoAccountCommand, rbac::RBAC_PERM_COMMAND_BANINFO_ACCOUNT, Console::Yes }, + { "character", HandleBanInfoCharacterCommand, rbac::RBAC_PERM_COMMAND_BANINFO_CHARACTER, Console::Yes }, + { "ip", HandleBanInfoIPCommand, rbac::RBAC_PERM_COMMAND_BANINFO_IP, Console::Yes } }; static ChatCommandTable banCommandTable = { - { "account", HandleBanAccountCommand, SEC_GAMEMASTER, Console::Yes }, - { "character", HandleBanCharacterCommand, SEC_GAMEMASTER, Console::Yes }, - { "playeraccount",HandleBanAccountByCharCommand, SEC_GAMEMASTER, Console::Yes }, - { "ip", HandleBanIPCommand, SEC_GAMEMASTER, Console::Yes } + { "account", HandleBanAccountCommand, rbac::RBAC_PERM_COMMAND_BAN_ACCOUNT, Console::Yes }, + { "character", HandleBanCharacterCommand, rbac::RBAC_PERM_COMMAND_BAN_CHARACTER, Console::Yes }, + { "playeraccount",HandleBanAccountByCharCommand, rbac::RBAC_PERM_COMMAND_BAN_PLAYERACCOUNT, Console::Yes }, + { "ip", HandleBanIPCommand, rbac::RBAC_PERM_COMMAND_BAN_IP, Console::Yes } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_bf.cpp b/src/server/scripts/Commands/cs_bf.cpp index 815f1fb20..3e8d0502b 100644 --- a/src/server/scripts/Commands/cs_bf.cpp +++ b/src/server/scripts/Commands/cs_bf.cpp @@ -18,10 +18,11 @@ #include "BattlefieldMgr.h" #include "Chat.h" #include "CommandScript.h" -#include "Language.h" #include "GameTime.h" +#include "Language.h" #include "ObjectAccessor.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -34,12 +35,12 @@ public: { static ChatCommandTable battlefieldcommandTable = { - { "start", HandleBattlefieldStart, SEC_ADMINISTRATOR, Console::Yes }, - { "stop", HandleBattlefieldEnd, SEC_ADMINISTRATOR, Console::Yes }, - { "switch", HandleBattlefieldSwitch, SEC_ADMINISTRATOR, Console::Yes }, - { "timer", HandleBattlefieldTimer, SEC_ADMINISTRATOR, Console::Yes }, - { "enable", HandleBattlefieldEnable, SEC_ADMINISTRATOR, Console::Yes }, - { "queue", HandleBattlefieldQueue, SEC_GAMEMASTER, Console::Yes } + { "start", HandleBattlefieldStart, rbac::RBAC_PERM_COMMAND_BF_START, Console::Yes }, + { "stop", HandleBattlefieldEnd, rbac::RBAC_PERM_COMMAND_BF_STOP, Console::Yes }, + { "switch", HandleBattlefieldSwitch, rbac::RBAC_PERM_COMMAND_BF_SWITCH, Console::Yes }, + { "timer", HandleBattlefieldTimer, rbac::RBAC_PERM_COMMAND_BF_TIMER, Console::Yes }, + { "enable", HandleBattlefieldEnable, rbac::RBAC_PERM_COMMAND_BF_ENABLE, Console::Yes }, + { "queue", HandleBattlefieldQueue, rbac::RBAC_PERM_COMMAND_BF_QUEUE, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_cache.cpp b/src/server/scripts/Commands/cs_cache.cpp index 2e05f5472..6f7899824 100644 --- a/src/server/scripts/Commands/cs_cache.cpp +++ b/src/server/scripts/Commands/cs_cache.cpp @@ -20,6 +20,7 @@ #include "Group.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -32,9 +33,9 @@ public: { static ChatCommandTable cacheCommandTable = { - { "info", HandleCacheInfoCommand, SEC_GAMEMASTER, Console::Yes }, - { "delete", HandleCacheDeleteCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "refresh", HandleCacheRefreshCommand, SEC_GAMEMASTER, Console::Yes } + { "info", HandleCacheInfoCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "delete", HandleCacheDeleteCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "refresh", HandleCacheRefreshCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_cast.cpp b/src/server/scripts/Commands/cs_cast.cpp index 654e2cf00..56c604a72 100644 --- a/src/server/scripts/Commands/cs_cast.cpp +++ b/src/server/scripts/Commands/cs_cast.cpp @@ -20,6 +20,7 @@ #include "Creature.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" #include "SpellInfo.h" #include "SpellMgr.h" @@ -34,12 +35,12 @@ public: { static ChatCommandTable castCommandTable = { - { "back", HandleCastBackCommand, SEC_GAMEMASTER, Console::No }, - { "dist", HandleCastDistCommand, SEC_GAMEMASTER, Console::No }, - { "self", HandleCastSelfCommand, SEC_GAMEMASTER, Console::No }, - { "target", HandleCastTargetCommad, SEC_GAMEMASTER, Console::No }, - { "dest", HandleCastDestCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleCastCommand, SEC_GAMEMASTER, Console::No } + { "back", HandleCastBackCommand, rbac::RBAC_PERM_COMMAND_CAST_BACK, Console::No }, + { "dist", HandleCastDistCommand, rbac::RBAC_PERM_COMMAND_CAST_DIST, Console::No }, + { "self", HandleCastSelfCommand, rbac::RBAC_PERM_COMMAND_CAST_SELF, Console::No }, + { "target", HandleCastTargetCommad, rbac::RBAC_PERM_COMMAND_CAST_TARGET, Console::No }, + { "dest", HandleCastDestCommand, rbac::RBAC_PERM_COMMAND_CAST_DEST, Console::No }, + { "", HandleCastCommand, rbac::RBAC_PERM_COMMAND_CAST, Console::No } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 11fc6d312..464b70512 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -25,6 +25,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "PlayerDump.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "Timer.h" #include "World.h" @@ -41,44 +42,45 @@ public: { static ChatCommandTable pdumpCommandTable = { - { "load", HandlePDumpLoadCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "write", HandlePDumpWriteCommand, SEC_ADMINISTRATOR, Console::Yes } + { "copy", HandlePDumpCopyCommand, rbac::RBAC_PERM_COMMAND_PDUMP_COPY, Console::Yes }, + { "load", HandlePDumpLoadCommand, rbac::RBAC_PERM_COMMAND_PDUMP_LOAD, Console::Yes }, + { "write", HandlePDumpWriteCommand, rbac::RBAC_PERM_COMMAND_PDUMP_WRITE, Console::Yes } }; static ChatCommandTable characterDeletedCommandTable = { - { "delete", HandleCharacterDeletedDeleteCommand, SEC_CONSOLE, Console::Yes }, - { "list", HandleCharacterDeletedListCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "restore", HandleCharacterDeletedRestoreCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "purge", HandleCharacterDeletedPurgeCommand, SEC_CONSOLE, Console::Yes } + { "delete", HandleCharacterDeletedDeleteCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED_DELETE, Console::Yes }, + { "list", HandleCharacterDeletedListCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED_LIST, Console::Yes }, + { "restore", HandleCharacterDeletedRestoreCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED_RESTORE, Console::Yes }, + { "purge", HandleCharacterDeletedPurgeCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED_OLD, Console::Yes } }; static ChatCommandTable characterCheckCommandTable = { - { "bank", HandleCharacterCheckBankCommand, SEC_GAMEMASTER, Console::Yes }, - { "bag", HandleCharacterCheckBagCommand, SEC_GAMEMASTER, Console::Yes }, - { "profession", HandleCharacterCheckProfessionCommand, SEC_GAMEMASTER, Console::Yes } + { "bank", HandleCharacterCheckBankCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHECK_BANK, Console::Yes }, + { "bag", HandleCharacterCheckBagCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHECK_BAG, Console::Yes }, + { "profession", HandleCharacterCheckProfessionCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHECK_PROFESSION, Console::Yes } }; static ChatCommandTable characterCommandTable = { - { "customize", HandleCharacterCustomizeCommand, SEC_GAMEMASTER, Console::Yes }, - { "changefaction", HandleCharacterChangeFactionCommand, SEC_GAMEMASTER, Console::Yes }, - { "changerace", HandleCharacterChangeRaceCommand, SEC_GAMEMASTER, Console::Yes }, - { "changeaccount", HandleCharacterChangeAccountCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "customize", HandleCharacterCustomizeCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE, Console::Yes }, + { "changefaction", HandleCharacterChangeFactionCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION, Console::Yes }, + { "changerace", HandleCharacterChangeRaceCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGERACE, Console::Yes }, + { "changeaccount", HandleCharacterChangeAccountCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT, Console::Yes }, { "check", characterCheckCommandTable }, - { "erase", HandleCharacterEraseCommand, SEC_CONSOLE, Console::Yes }, + { "erase", HandleCharacterEraseCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_ERASE, Console::Yes }, { "deleted", characterDeletedCommandTable }, - { "level", HandleCharacterLevelCommand, SEC_GAMEMASTER, Console::Yes }, - { "rename", HandleCharacterRenameCommand, SEC_GAMEMASTER, Console::Yes }, - { "reputation", HandleCharacterReputationCommand, SEC_GAMEMASTER, Console::Yes }, - { "titles", HandleCharacterTitlesCommand, SEC_GAMEMASTER, Console::Yes } + { "level", HandleCharacterLevelCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, Console::Yes }, + { "rename", HandleCharacterRenameCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_RENAME, Console::Yes }, + { "reputation", HandleCharacterReputationCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_REPUTATION, Console::Yes }, + { "titles", HandleCharacterTitlesCommand, rbac::RBAC_PERM_COMMAND_CHARACTER_TITLES, Console::Yes } }; static ChatCommandTable commandTable = { { "character", characterCommandTable }, - { "levelup", HandleLevelUpCommand, SEC_GAMEMASTER, Console::No }, + { "levelup", HandleLevelUpCommand, rbac::RBAC_PERM_COMMAND_LEVELUP, Console::No }, { "pdump", pdumpCommandTable } }; diff --git a/src/server/scripts/Commands/cs_cheat.cpp b/src/server/scripts/Commands/cs_cheat.cpp index 2b067ab78..880dc772c 100644 --- a/src/server/scripts/Commands/cs_cheat.cpp +++ b/src/server/scripts/Commands/cs_cheat.cpp @@ -19,6 +19,8 @@ #include "CommandScript.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" +#include "WorldSession.h" using namespace Acore::ChatCommands; @@ -31,14 +33,14 @@ public: { static ChatCommandTable cheatCommandTable = { - { "god", HandleGodModeCheatCommand, SEC_GAMEMASTER, Console::No }, - { "casttime", HandleCasttimeCheatCommand, SEC_GAMEMASTER, Console::No }, - { "cooldown", HandleCoolDownCheatCommand, SEC_GAMEMASTER, Console::No }, - { "power", HandlePowerCheatCommand, SEC_GAMEMASTER, Console::No }, - { "waterwalk", HandleWaterWalkCheatCommand, SEC_GAMEMASTER, Console::No }, - { "status", HandleCheatStatusCommand, SEC_GAMEMASTER, Console::No }, - { "taxi", HandleTaxiCheatCommand, SEC_GAMEMASTER, Console::No }, - { "explore", HandleExploreCheatCommand, SEC_GAMEMASTER, Console::No } + { "god", HandleGodModeCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_GOD, Console::No }, + { "casttime", HandleCasttimeCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_CASTTIME, Console::No }, + { "cooldown", HandleCoolDownCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_COOLDOWN, Console::No }, + { "power", HandlePowerCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_POWER, Console::No }, + { "waterwalk", HandleWaterWalkCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_WATERWALK, Console::No }, + { "status", HandleCheatStatusCommand, rbac::RBAC_PERM_COMMAND_CHEAT_STATUS, Console::No }, + { "taxi", HandleTaxiCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_TAXI, Console::No }, + { "explore", HandleExploreCheatCommand, rbac::RBAC_PERM_COMMAND_CHEAT_EXPLORE, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 8c80529d9..401446077 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -37,6 +37,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "PoolMgr.h" +#include "RBAC.h" #include "RaceMgr.h" #include "ScriptMgr.h" #include "Transport.h" @@ -57,71 +58,71 @@ public: { static ChatCommandTable debugPlayCommandTable = { - { "cinematic", HandleDebugPlayCinematicCommand, SEC_ADMINISTRATOR, Console::No }, - { "movie", HandleDebugPlayMovieCommand, SEC_ADMINISTRATOR, Console::No }, - { "sound", HandleDebugPlaySoundCommand, SEC_ADMINISTRATOR, Console::No }, - { "music", HandleDebugPlayMusicCommand, SEC_ADMINISTRATOR, Console::No }, - { "visual", HandleDebugVisualCommand, SEC_ADMINISTRATOR, Console::No } + { "cinematic", HandleDebugPlayCinematicCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "movie", HandleDebugPlayMovieCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "sound", HandleDebugPlaySoundCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "music", HandleDebugPlayMusicCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "visual", HandleDebugVisualCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No } }; static ChatCommandTable debugSendCommandTable = { - { "buyerror", HandleDebugSendBuyErrorCommand, SEC_ADMINISTRATOR, Console::No }, - { "channelnotify", HandleDebugSendChannelNotifyCommand, SEC_ADMINISTRATOR, Console::No }, - { "chatmessage", HandleDebugSendChatMsgCommand, SEC_ADMINISTRATOR, Console::No }, - { "equiperror", HandleDebugSendEquipErrorCommand, SEC_ADMINISTRATOR, Console::No }, - { "largepacket", HandleDebugSendLargePacketCommand, SEC_ADMINISTRATOR, Console::No }, - { "opcode", HandleDebugSendOpcodeCommand, SEC_ADMINISTRATOR, Console::No }, - { "qpartymsg", HandleDebugSendQuestPartyMsgCommand, SEC_ADMINISTRATOR, Console::No }, - { "qinvalidmsg", HandleDebugSendQuestInvalidMsgCommand, SEC_ADMINISTRATOR, Console::No }, - { "sellerror", HandleDebugSendSellErrorCommand, SEC_ADMINISTRATOR, Console::No }, - { "setphaseshift", HandleDebugSendSetPhaseShiftCommand, SEC_ADMINISTRATOR, Console::No }, - { "spellfail", HandleDebugSendSpellFailCommand, SEC_ADMINISTRATOR, Console::No } + { "buyerror", HandleDebugSendBuyErrorCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "channelnotify", HandleDebugSendChannelNotifyCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "chatmessage", HandleDebugSendChatMsgCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "equiperror", HandleDebugSendEquipErrorCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "largepacket", HandleDebugSendLargePacketCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "opcode", HandleDebugSendOpcodeCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "qpartymsg", HandleDebugSendQuestPartyMsgCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "qinvalidmsg", HandleDebugSendQuestInvalidMsgCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "sellerror", HandleDebugSendSellErrorCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "setphaseshift", HandleDebugSendSetPhaseShiftCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "spellfail", HandleDebugSendSpellFailCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No } }; static ChatCommandTable debugCommandTable = { - { "setbit", HandleDebugSet32BitCommand, SEC_ADMINISTRATOR, Console::No }, - { "threat", HandleDebugThreatListCommand, SEC_ADMINISTRATOR, Console::No }, - { "threatinfo", HandleDebugThreatInfoCommand, SEC_ADMINISTRATOR, Console::No }, - { "combat", HandleDebugCombatListCommand, SEC_ADMINISTRATOR, Console::No }, - { "hostile", HandleDebugHostileRefListCommand, SEC_ADMINISTRATOR, Console::No }, - { "anim", HandleDebugAnimCommand, SEC_ADMINISTRATOR, Console::No }, - { "arena", HandleDebugArenaCommand, SEC_ADMINISTRATOR, Console::No }, - { "bg", HandleDebugBattlegroundCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "cooldown", HandleDebugCooldownCommand, SEC_ADMINISTRATOR, Console::No }, - { "getitemstate", HandleDebugGetItemStateCommand, SEC_ADMINISTRATOR, Console::No }, - { "lootrecipient", HandleDebugGetLootRecipientCommand, SEC_ADMINISTRATOR, Console::No }, - { "getvalue", HandleDebugGetValueCommand, SEC_ADMINISTRATOR, Console::No }, - { "getitemvalue", HandleDebugGetItemValueCommand, SEC_ADMINISTRATOR, Console::No }, - { "Mod32Value", HandleDebugMod32ValueCommand, SEC_ADMINISTRATOR, Console::No }, + { "setbit", HandleDebugSet32BitCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "threat", HandleDebugThreatListCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "threatinfo", HandleDebugThreatInfoCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "combat", HandleDebugCombatListCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "hostile", HandleDebugHostileRefListCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "anim", HandleDebugAnimCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "arena", HandleDebugArenaCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "bg", HandleDebugBattlegroundCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes}, + { "cooldown", HandleDebugCooldownCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "getitemstate", HandleDebugGetItemStateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "lootrecipient", HandleDebugGetLootRecipientCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "getvalue", HandleDebugGetValueCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "getitemvalue", HandleDebugGetItemValueCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "Mod32Value", HandleDebugMod32ValueCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, { "play", debugPlayCommandTable }, { "send", debugSendCommandTable }, - { "setaurastate", HandleDebugSetAuraStateCommand, SEC_ADMINISTRATOR, Console::No }, - { "setitemvalue", HandleDebugSetItemValueCommand, SEC_ADMINISTRATOR, Console::No }, - { "setvalue", HandleDebugSetValueCommand, SEC_ADMINISTRATOR, Console::No }, - { "spawnvehicle", HandleDebugSpawnVehicleCommand, SEC_ADMINISTRATOR, Console::No }, - { "setvid", HandleDebugSetVehicleIdCommand, SEC_ADMINISTRATOR, Console::No }, - { "entervehicle", HandleDebugEnterVehicleCommand, SEC_ADMINISTRATOR, Console::No }, - { "uws", HandleDebugUpdateWorldStateCommand, SEC_ADMINISTRATOR, Console::No }, - { "update", HandleDebugUpdateCommand, SEC_ADMINISTRATOR, Console::No }, - { "itemexpire", HandleDebugItemExpireCommand, SEC_ADMINISTRATOR, Console::No }, - { "areatriggers", HandleDebugAreaTriggersCommand, SEC_ADMINISTRATOR, Console::No }, - { "lfg", HandleDebugDungeonFinderCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "loot", HandleDebugLootCommand, SEC_GAMEMASTER, Console::Yes}, - { "los", HandleDebugLoSCommand, SEC_ADMINISTRATOR, Console::No }, - { "moveflags", HandleDebugMoveflagsCommand, SEC_ADMINISTRATOR, Console::No }, - { "unitstate", HandleDebugUnitStateCommand, SEC_ADMINISTRATOR, Console::No }, - { "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No }, - { "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No }, - { "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No }, - { "visibilitydata", HandleDebugVisibilityDataCommand, SEC_ADMINISTRATOR, Console::No }, - { "factionchange", HandleDebugFactionChangeCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "zonestats", HandleDebugZoneStatsCommand, SEC_MODERATOR, Console::Yes} + { "setaurastate", HandleDebugSetAuraStateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "setitemvalue", HandleDebugSetItemValueCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "setvalue", HandleDebugSetValueCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "spawnvehicle", HandleDebugSpawnVehicleCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "setvid", HandleDebugSetVehicleIdCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "entervehicle", HandleDebugEnterVehicleCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "uws", HandleDebugUpdateWorldStateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "update", HandleDebugUpdateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "itemexpire", HandleDebugItemExpireCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "areatriggers", HandleDebugAreaTriggersCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "lfg", HandleDebugDungeonFinderCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes}, + { "loot", HandleDebugLootCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes}, + { "los", HandleDebugLoSCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "moveflags", HandleDebugMoveflagsCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "unitstate", HandleDebugUnitStateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "objectcount", HandleDebugObjectCountCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes}, + { "dummy", HandleDebugDummyCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "mapdata", HandleDebugMapDataCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "boundary", HandleDebugBoundaryCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "visibilitydata", HandleDebugVisibilityDataCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "factionchange", HandleDebugFactionChangeCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes}, + { "zonestats", HandleDebugZoneStatsCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes} }; static ChatCommandTable commandTable = { { "debug", debugCommandTable }, - { "wpgps", HandleWPGPSCommand, SEC_ADMINISTRATOR, Console::No } + { "wpgps", HandleWPGPSCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No } }; return commandTable; } diff --git a/src/server/scripts/Commands/cs_deserter.cpp b/src/server/scripts/Commands/cs_deserter.cpp index 860046d10..1e2e64066 100644 --- a/src/server/scripts/Commands/cs_deserter.cpp +++ b/src/server/scripts/Commands/cs_deserter.cpp @@ -27,6 +27,7 @@ #include "GroupMgr.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" #include "SpellAuras.h" using namespace Acore::ChatCommands; @@ -50,15 +51,15 @@ public: { static ChatCommandTable deserterInstanceCommandTable = { - { "add", HandleDeserterInstanceAdd, SEC_ADMINISTRATOR, Console::Yes }, - { "remove all", HandleDeserterInstanceRemoveAll, SEC_ADMINISTRATOR, Console::Yes }, - { "remove", HandleDeserterInstanceRemove, SEC_ADMINISTRATOR, Console::Yes } + { "add", HandleDeserterInstanceAdd, rbac::RBAC_PERM_COMMAND_DESERTER_INSTANCE_ADD, Console::Yes }, + { "remove all", HandleDeserterInstanceRemoveAll, rbac::RBAC_PERM_COMMAND_DESERTER_INSTANCE_REMOVE, Console::Yes }, + { "remove", HandleDeserterInstanceRemove, rbac::RBAC_PERM_COMMAND_DESERTER_INSTANCE_REMOVE, Console::Yes } }; static ChatCommandTable deserterBGCommandTable = { - { "add", HandleDeserterBGAdd, SEC_ADMINISTRATOR, Console::Yes }, - { "remove all", HandleDeserterBGRemoveAll, SEC_ADMINISTRATOR, Console::Yes }, - { "remove", HandleDeserterBGRemove, SEC_ADMINISTRATOR, Console::Yes } + { "add", HandleDeserterBGAdd, rbac::RBAC_PERM_COMMAND_DESERTER_BG_ADD, Console::Yes }, + { "remove all", HandleDeserterBGRemoveAll, rbac::RBAC_PERM_COMMAND_DESERTER_BG_REMOVE, Console::Yes }, + { "remove", HandleDeserterBGRemove, rbac::RBAC_PERM_COMMAND_DESERTER_BG_REMOVE, Console::Yes } }; static ChatCommandTable deserterCommandTable = diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp index 2846f59a4..c0e35098d 100644 --- a/src/server/scripts/Commands/cs_disable.cpp +++ b/src/server/scripts/Commands/cs_disable.cpp @@ -21,6 +21,8 @@ #include "Language.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" +#include "Player.h" +#include "RBAC.h" #include "SpellMgr.h" using namespace Acore::ChatCommands; @@ -34,21 +36,21 @@ public: { static ChatCommandTable removeDisableCommandTable = { - { "spell", HandleRemoveDisableSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest", HandleRemoveDisableQuestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "map", HandleRemoveDisableMapCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "battleground", HandleRemoveDisableBattlegroundCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "outdoorpvp", HandleRemoveDisableOutdoorPvPCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "vmap", HandleRemoveDisableVmapCommand, SEC_ADMINISTRATOR, Console::Yes } + { "spell", HandleRemoveDisableSpellCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_SPELL, Console::Yes }, + { "quest", HandleRemoveDisableQuestCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_QUEST, Console::Yes }, + { "map", HandleRemoveDisableMapCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_MAP, Console::Yes }, + { "battleground", HandleRemoveDisableBattlegroundCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_BATTLEGROUND, Console::Yes }, + { "outdoorpvp", HandleRemoveDisableOutdoorPvPCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_OUTDOORPVP, Console::Yes }, + { "vmap", HandleRemoveDisableVmapCommand, rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_VMAP, Console::Yes } }; static ChatCommandTable addDisableCommandTable = { - { "spell", HandleAddDisableSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest", HandleAddDisableQuestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "map", HandleAddDisableMapCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "battleground", HandleAddDisableBattlegroundCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "outdoorpvp", HandleAddDisableOutdoorPvPCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "vmap", HandleAddDisableVmapCommand, SEC_ADMINISTRATOR, Console::Yes } + { "spell", HandleAddDisableSpellCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_SPELL, Console::Yes }, + { "quest", HandleAddDisableQuestCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_QUEST, Console::Yes }, + { "map", HandleAddDisableMapCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_MAP, Console::Yes }, + { "battleground", HandleAddDisableBattlegroundCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_BATTLEGROUND, Console::Yes }, + { "outdoorpvp", HandleAddDisableOutdoorPvPCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_OUTDOORPVP, Console::Yes }, + { "vmap", HandleAddDisableVmapCommand, rbac::RBAC_PERM_COMMAND_DISABLE_ADD_VMAP, Console::Yes } }; static ChatCommandTable disableCommandTable = { diff --git a/src/server/scripts/Commands/cs_event.cpp b/src/server/scripts/Commands/cs_event.cpp index 1b101e086..97d44cb60 100644 --- a/src/server/scripts/Commands/cs_event.cpp +++ b/src/server/scripts/Commands/cs_event.cpp @@ -20,6 +20,7 @@ #include "GameEventMgr.h" #include "GameTime.h" #include "Language.h" +#include "RBAC.h" #include "Timer.h" using namespace Acore::ChatCommands; @@ -35,10 +36,10 @@ public: { static ChatCommandTable eventCommandTable = { - { "activelist", HandleEventActiveListCommand, SEC_GAMEMASTER, Console::Yes }, - { "start", HandleEventStartCommand, SEC_GAMEMASTER, Console::Yes }, - { "stop", HandleEventStopCommand, SEC_GAMEMASTER, Console::Yes }, - { "info", HandleEventInfoCommand, SEC_GAMEMASTER, Console::Yes } + { "activelist", HandleEventActiveListCommand, rbac::RBAC_PERM_COMMAND_EVENT_ACTIVELIST, Console::Yes }, + { "start", HandleEventStartCommand, rbac::RBAC_PERM_COMMAND_EVENT_START, Console::Yes }, + { "stop", HandleEventStopCommand, rbac::RBAC_PERM_COMMAND_EVENT_STOP, Console::Yes }, + { "info", HandleEventInfoCommand, rbac::RBAC_PERM_COMMAND_EVENT_INFO, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_gear.cpp b/src/server/scripts/Commands/cs_gear.cpp index b67fc456d..c2ba986e2 100644 --- a/src/server/scripts/Commands/cs_gear.cpp +++ b/src/server/scripts/Commands/cs_gear.cpp @@ -19,6 +19,8 @@ #include "CommandScript.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" +#include "WorldSession.h" using namespace Acore::ChatCommands; @@ -31,8 +33,8 @@ public: { static ChatCommandTable gearCommandTable = { - { "repair", HandleGearRepairCommand, SEC_GAMEMASTER, Console::No }, - { "stats", HandleGearStatsCommand, SEC_PLAYER, Console::No } + { "repair", HandleGearRepairCommand, rbac::RBAC_PERM_COMMAND_GEAR_REPAIR, Console::No }, + { "stats", HandleGearStatsCommand, rbac::RBAC_PERM_COMMAND_GEAR_STATS, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index b1379ff24..0138f65c1 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -23,6 +23,7 @@ #include "ObjectAccessor.h" #include "Opcodes.h" #include "Player.h" +#include "RBAC.h" #include "Realm.h" #include "World.h" #include "WorldSession.h" @@ -38,14 +39,14 @@ public: { static ChatCommandTable gmCommandTable = { - { "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No }, - { "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No }, - { "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes }, - { "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No }, - { "on", HandleGMOnCommand, SEC_MODERATOR, Console::No }, - { "off", HandleGMOffCommand, SEC_MODERATOR, Console::No }, - { "spectator", HandleGMSpectatorCommand, SEC_GAMEMASTER, Console::No }, + { "chat", HandleGMChatCommand, rbac::RBAC_PERM_COMMAND_GM_CHAT, Console::No }, + { "fly", HandleGMFlyCommand, rbac::RBAC_PERM_COMMAND_GM_FLY, Console::No }, + { "ingame", HandleGMListIngameCommand, rbac::RBAC_PERM_COMMAND_GM_INGAME, Console::Yes }, + { "list", HandleGMListFullCommand, rbac::RBAC_PERM_COMMAND_GM_LIST, Console::Yes }, + { "visible", HandleGMVisibleCommand, rbac::RBAC_PERM_COMMAND_GM_VISIBLE, Console::No }, + { "on", HandleGMOnCommand, rbac::RBAC_PERM_COMMAND_GM, Console::No }, + { "off", HandleGMOffCommand, rbac::RBAC_PERM_COMMAND_GM, Console::No }, + { "spectator", HandleGMSpectatorCommand, rbac::RBAC_PERM_COMMAND_GM, Console::No }, }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 88a7df172..7f575ac17 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -22,6 +22,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "TicketMgr.h" #include "Transport.h" @@ -39,19 +40,19 @@ public: { static ChatCommandTable goCommandTable = { - { "creature", HandleGoCreatureSpawnIdCommand, SEC_MODERATOR, Console::No }, - { "creature id", HandleGoCreatureCIdCommand, SEC_MODERATOR, Console::No }, - { "creature name", HandleGoCreatureNameCommand, SEC_MODERATOR, Console::No }, - { "gameobject", HandleGoGameObjectSpawnIdCommand, SEC_MODERATOR, Console::No }, - { "gameobject id", HandleGoGameObjectGOIdCommand, SEC_MODERATOR, Console::No }, - { "graveyard", HandleGoGraveyardCommand, SEC_MODERATOR, Console::No }, - { "grid", HandleGoGridCommand, SEC_MODERATOR, Console::No }, - { "taxinode", HandleGoTaxinodeCommand, SEC_MODERATOR, Console::No }, - { "trigger", HandleGoTriggerCommand, SEC_MODERATOR, Console::No }, - { "zonexy", HandleGoZoneXYCommand, SEC_MODERATOR, Console::No }, - { "xyz", HandleGoXYZCommand, SEC_MODERATOR, Console::No }, - { "ticket", HandleGoTicketCommand, SEC_GAMEMASTER, Console::No }, - { "quest", HandleGoQuestCommand, SEC_MODERATOR, Console::No }, + { "creature", HandleGoCreatureSpawnIdCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "creature id", HandleGoCreatureCIdCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "creature name", HandleGoCreatureNameCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "gameobject", HandleGoGameObjectSpawnIdCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "gameobject id", HandleGoGameObjectGOIdCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "graveyard", HandleGoGraveyardCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "grid", HandleGoGridCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "taxinode", HandleGoTaxinodeCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "trigger", HandleGoTriggerCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "zonexy", HandleGoZoneXYCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "xyz", HandleGoXYZCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "ticket", HandleGoTicketCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, + { "quest", HandleGoQuestCommand, rbac::RBAC_PERM_COMMAND_GO, Console::No }, }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 79ce132bd..1bfed4f58 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -28,6 +28,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "PoolMgr.h" +#include "RBAC.h" #include "Transport.h" #include @@ -45,21 +46,21 @@ public: { static ChatCommandTable gobjectCommandTable = { - { "activate", HandleGameObjectActivateCommand, SEC_GAMEMASTER, Console::No }, - { "delete", HandleGameObjectDeleteCommand, SEC_ADMINISTRATOR, Console::No }, - { "info", HandleGameObjectInfoCommand, SEC_MODERATOR, Console::No }, - { "move", HandleGameObjectMoveCommand, SEC_ADMINISTRATOR, Console::No }, - { "near", HandleGameObjectNearCommand, SEC_MODERATOR, Console::No }, - { "target", HandleGameObjectTargetCommand, SEC_MODERATOR, Console::No }, - { "turn", HandleGameObjectTurnCommand, SEC_ADMINISTRATOR, Console::No }, - { "add temp", HandleGameObjectAddTempCommand, SEC_GAMEMASTER, Console::No }, - { "add", HandleGameObjectAddCommand, SEC_ADMINISTRATOR, Console::No }, - { "load", HandleGameObjectLoadCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "set phase", HandleGameObjectSetPhaseCommand, SEC_ADMINISTRATOR, Console::No }, - { "set state", HandleGameObjectSetStateCommand, SEC_ADMINISTRATOR, Console::No }, - { "respawn", HandleGameObjectRespawn, SEC_GAMEMASTER, Console::No }, - { "spawngroup", HandleGameObjectSpawnGroupCommand, SEC_ADMINISTRATOR, Console::No }, - { "despawngroup", HandleGameObjectDespawnGroupCommand, SEC_ADMINISTRATOR, Console::No } + { "activate", HandleGameObjectActivateCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_ACTIVATE, Console::No }, + { "delete", HandleGameObjectDeleteCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_DELETE, Console::No }, + { "info", HandleGameObjectInfoCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_INFO, Console::No }, + { "move", HandleGameObjectMoveCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_MOVE, Console::No }, + { "near", HandleGameObjectNearCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_NEAR, Console::No }, + { "target", HandleGameObjectTargetCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_TARGET, Console::No }, + { "turn", HandleGameObjectTurnCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_TURN, Console::No }, + { "add temp", HandleGameObjectAddTempCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_ADD_TEMP, Console::No }, + { "add", HandleGameObjectAddCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_ADD, Console::No }, + { "load", HandleGameObjectLoadCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_LOAD, Console::Yes }, + { "set phase", HandleGameObjectSetPhaseCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_SET_PHASE, Console::No }, + { "set state", HandleGameObjectSetStateCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_SET_STATE, Console::No }, + { "respawn", HandleGameObjectRespawn, rbac::RBAC_PERM_COMMAND_GOBJECT_ACTIVATE, Console::No }, + { "spawngroup", HandleGameObjectSpawnGroupCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_ADD, Console::No }, + { "despawngroup", HandleGameObjectDespawnGroupCommand, rbac::RBAC_PERM_COMMAND_GOBJECT_DELETE, Console::No } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index 7be8d6674..83b4e001a 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -20,6 +20,7 @@ #include "GroupMgr.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -32,12 +33,12 @@ public: { static ChatCommandTable groupCommandTable = { - { "list", HandleGroupListCommand, SEC_GAMEMASTER, Console::Yes }, - { "join", HandleGroupJoinCommand, SEC_GAMEMASTER, Console::No }, - { "remove", HandleGroupRemoveCommand, SEC_GAMEMASTER, Console::No }, - { "disband", HandleGroupDisbandCommand, SEC_GAMEMASTER, Console::No }, - { "revive", HandleGroupReviveCommand, SEC_GAMEMASTER, Console::No }, - { "leader", HandleGroupLeaderCommand, SEC_GAMEMASTER, Console::No } + { "list", HandleGroupListCommand, rbac::RBAC_PERM_COMMAND_GROUP_LIST, Console::Yes }, + { "join", HandleGroupJoinCommand, rbac::RBAC_PERM_COMMAND_GROUP_JOIN, Console::No }, + { "remove", HandleGroupRemoveCommand, rbac::RBAC_PERM_COMMAND_GROUP_REMOVE, Console::No }, + { "disband", HandleGroupDisbandCommand, rbac::RBAC_PERM_COMMAND_GROUP_DISBAND, Console::No }, + { "revive", HandleGroupReviveCommand, rbac::RBAC_PERM_COMMAND_GROUP_REVIVE, Console::No }, + { "leader", HandleGroupLeaderCommand, rbac::RBAC_PERM_COMMAND_GROUP_LEADER, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 45c55ddf0..1980344de 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -19,6 +19,7 @@ #include "CommandScript.h" #include "Guild.h" #include "GuildMgr.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -31,13 +32,13 @@ public: { static ChatCommandTable guildCommandTable = { - { "create", HandleGuildCreateCommand, SEC_GAMEMASTER, Console::Yes }, - { "delete", HandleGuildDeleteCommand, SEC_GAMEMASTER, Console::Yes }, - { "invite", HandleGuildInviteCommand, SEC_GAMEMASTER, Console::Yes }, - { "uninvite", HandleGuildUninviteCommand, SEC_GAMEMASTER, Console::Yes }, - { "rank", HandleGuildRankCommand, SEC_GAMEMASTER, Console::Yes }, - { "rename", HandleGuildRenameCommand, SEC_GAMEMASTER, Console::Yes }, - { "info", HandleGuildInfoCommand, SEC_GAMEMASTER, Console::Yes } + { "create", HandleGuildCreateCommand, rbac::RBAC_PERM_COMMAND_GUILD_CREATE, Console::Yes }, + { "delete", HandleGuildDeleteCommand, rbac::RBAC_PERM_COMMAND_GUILD_DELETE, Console::Yes }, + { "invite", HandleGuildInviteCommand, rbac::RBAC_PERM_COMMAND_GUILD_INVITE, Console::Yes }, + { "uninvite", HandleGuildUninviteCommand, rbac::RBAC_PERM_COMMAND_GUILD_UNINVITE, Console::Yes }, + { "rank", HandleGuildRankCommand, rbac::RBAC_PERM_COMMAND_GUILD_RANK, Console::Yes }, + { "rename", HandleGuildRenameCommand, rbac::RBAC_PERM_COMMAND_GUILD_RENAME, Console::Yes }, + { "info", HandleGuildInfoCommand, rbac::RBAC_PERM_COMMAND_GUILD_INFO, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_honor.cpp b/src/server/scripts/Commands/cs_honor.cpp index af83d0b9f..f96f0c92d 100644 --- a/src/server/scripts/Commands/cs_honor.cpp +++ b/src/server/scripts/Commands/cs_honor.cpp @@ -19,6 +19,8 @@ #include "CommandScript.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" +#include "WorldSession.h" using namespace Acore::ChatCommands; @@ -31,14 +33,14 @@ public: { static ChatCommandTable honorAddCommandTable = { - { "kill", HandleHonorAddKillCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleHonorAddCommand, SEC_GAMEMASTER, Console::No } + { "kill", HandleHonorAddKillCommand, rbac::RBAC_PERM_COMMAND_HONOR_ADD_KILL, Console::No }, + { "", HandleHonorAddCommand, rbac::RBAC_PERM_COMMAND_HONOR_ADD, Console::No } }; static ChatCommandTable honorCommandTable = { { "add", honorAddCommandTable }, - { "update", HandleHonorUpdateCommand, SEC_GAMEMASTER, Console::No } + { "update", HandleHonorUpdateCommand, rbac::RBAC_PERM_COMMAND_HONOR_UPDATE, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_instance.cpp b/src/server/scripts/Commands/cs_instance.cpp index 078594a8a..009624f79 100644 --- a/src/server/scripts/Commands/cs_instance.cpp +++ b/src/server/scripts/Commands/cs_instance.cpp @@ -25,6 +25,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -37,12 +38,12 @@ public: { static ChatCommandTable instanceCommandTable = { - { "listbinds", HandleInstanceListBindsCommand, SEC_MODERATOR, Console::No }, - { "unbind", HandleInstanceUnbindCommand, SEC_GAMEMASTER, Console::No }, - { "stats", HandleInstanceStatsCommand, SEC_MODERATOR, Console::Yes }, - { "savedata", HandleInstanceSaveDataCommand, SEC_ADMINISTRATOR, Console::No }, - { "setbossstate", HandleInstanceSetBossStateCommand, SEC_GAMEMASTER, Console::Yes }, - { "getbossstate", HandleInstanceGetBossStateCommand, SEC_MODERATOR, Console::Yes }, + { "listbinds", HandleInstanceListBindsCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_LISTBINDS, Console::No }, + { "unbind", HandleInstanceUnbindCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_UNBIND, Console::No }, + { "stats", HandleInstanceStatsCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_STATS, Console::Yes }, + { "savedata", HandleInstanceSaveDataCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_SAVEDATA, Console::No }, + { "setbossstate", HandleInstanceSetBossStateCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_SET_BOSS_STATE, Console::Yes }, + { "getbossstate", HandleInstanceGetBossStateCommand, rbac::RBAC_PERM_COMMAND_INSTANCE_GET_BOSS_STATE, Console::Yes }, }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_inventory.cpp b/src/server/scripts/Commands/cs_inventory.cpp index 43fae2e91..80ece0d0d 100644 --- a/src/server/scripts/Commands/cs_inventory.cpp +++ b/src/server/scripts/Commands/cs_inventory.cpp @@ -19,6 +19,8 @@ #include "CommandScript.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" +#include "WorldSession.h" constexpr std::array bagSpecsToString = { @@ -70,7 +72,7 @@ public: { static ChatCommandTable inventoryCommandTable = { - { "count", HandleInventoryCountCommand, SEC_MODERATOR, Console::No } + { "count", HandleInventoryCountCommand, rbac::RBAC_PERM_COMMAND_ADDITEM, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_item.cpp b/src/server/scripts/Commands/cs_item.cpp index 711f2532e..e866443fc 100644 --- a/src/server/scripts/Commands/cs_item.cpp +++ b/src/server/scripts/Commands/cs_item.cpp @@ -22,6 +22,7 @@ #include "Language.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -34,14 +35,14 @@ public: { static ChatCommandTable HandleItemRestoreCommandTable = { - { "list", HandleItemRestoreListCommand, SEC_GAMEMASTER, Console::Yes }, - { "", HandleItemRestoreCommand, SEC_GAMEMASTER, Console::Yes }, + { "list", HandleItemRestoreListCommand, rbac::RBAC_PERM_COMMAND_ITEM_RESTORE_LIST, Console::Yes }, + { "", HandleItemRestoreCommand, rbac::RBAC_PERM_COMMAND_ITEM_RESTORE, Console::Yes }, }; static ChatCommandTable itemCommandTable = { { "restore", HandleItemRestoreCommandTable }, - { "move", HandleItemMoveCommand, SEC_GAMEMASTER, Console::Yes }, - { "refund", HandleItemRefundCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "move", HandleItemMoveCommand, rbac::RBAC_PERM_COMMAND_ITEMMOVE, Console::Yes }, + { "refund", HandleItemRefundCommand, rbac::RBAC_PERM_COMMAND_ITEM_REFUND, Console::Yes }, }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 1b5cc4b89..b86e56662 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -21,6 +21,7 @@ #include "Pet.h" #include "Player.h" #include "PlayerCommand.h" +#include "RBAC.h" #include "SpellInfo.h" #include "SpellMgr.h" @@ -35,33 +36,33 @@ public: { static ChatCommandTable learnAllMyCommandTable = { - { "class", HandleLearnAllMyClassCommand, SEC_GAMEMASTER, Console::No }, - { "pettalents", HandleLearnAllMyPetTalentsCommand, SEC_GAMEMASTER, Console::No }, - { "trainer", HandleLearnAllMyTrainerSpellsCommand, SEC_GAMEMASTER, Console::No }, - { "talents", HandleLearnAllMyTalentsCommand, SEC_GAMEMASTER, Console::No }, - { "quest", HandleLearnAllMyQuestSpells, SEC_GAMEMASTER, Console::No } + { "class", HandleLearnAllMyClassCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_MY_CLASS, Console::No }, + { "pettalents", HandleLearnAllMyPetTalentsCommand, rbac::RBAC_PERM_COMMAND_LEARN_MY_PETTALENTS, Console::No }, + { "trainer", HandleLearnAllMyTrainerSpellsCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_MY_SPELLS, Console::No }, + { "talents", HandleLearnAllMyTalentsCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_TALENTS, Console::No }, + { "quest", HandleLearnAllMyQuestSpells, rbac::RBAC_PERM_COMMAND_LEARN_ALL_MY_SPELLS, Console::No } }; static ChatCommandTable learnAllCommandTable = { { "my", learnAllMyCommandTable }, - { "gm", HandleLearnAllGMCommand, SEC_GAMEMASTER, Console::No }, - { "crafts", HandleLearnAllCraftsCommand, SEC_GAMEMASTER, Console::No }, - { "default", HandleLearnAllDefaultCommand, SEC_GAMEMASTER, Console::No }, - { "lang", HandleLearnAllLangCommand, SEC_GAMEMASTER, Console::No }, - { "recipes", HandleLearnAllRecipesCommand, SEC_GAMEMASTER, Console::No }, + { "gm", HandleLearnAllGMCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_GM, Console::No }, + { "crafts", HandleLearnAllCraftsCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_CRAFTS, Console::No }, + { "default", HandleLearnAllDefaultCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_DEFAULT, Console::No }, + { "lang", HandleLearnAllLangCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_LANG, Console::No }, + { "recipes", HandleLearnAllRecipesCommand, rbac::RBAC_PERM_COMMAND_LEARN_ALL_RECIPES, Console::No }, }; static ChatCommandTable learnCommandTable = { { "all", learnAllCommandTable }, - { "", HandleLearnCommand, SEC_GAMEMASTER, Console::No } + { "", HandleLearnCommand, rbac::RBAC_PERM_COMMAND_LEARN, Console::No } }; static ChatCommandTable commandTable = { { "learn", learnCommandTable }, - { "unlearn", HandleUnLearnCommand, SEC_GAMEMASTER, Console::No } + { "unlearn", HandleUnLearnCommand, rbac::RBAC_PERM_COMMAND_UNLEARN, Console::No } }; return commandTable; } diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp index 693ab1585..c147d64f0 100644 --- a/src/server/scripts/Commands/cs_lfg.cpp +++ b/src/server/scripts/Commands/cs_lfg.cpp @@ -21,6 +21,7 @@ #include "LFGMgr.h" #include "Language.h" #include "Player.h" +#include "RBAC.h" void GetPlayerInfo(ChatHandler* handler, Player* player) { @@ -47,12 +48,12 @@ public: { static ChatCommandTable lfgCommandTable = { - { "player", HandleLfgPlayerInfoCommand, SEC_MODERATOR, Console::No }, - { "group", HandleLfgGroupInfoCommand, SEC_MODERATOR, Console::No }, - { "queue", HandleLfgQueueInfoCommand, SEC_MODERATOR, Console::Yes }, - { "clean", HandleLfgCleanCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "options", HandleLfgOptionsCommand, SEC_GAMEMASTER, Console::Yes }, - { "cooldown", HandleLfgCooldownClearCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "player", HandleLfgPlayerInfoCommand, rbac::RBAC_PERM_COMMAND_LFG_PLAYER, Console::No }, + { "group", HandleLfgGroupInfoCommand, rbac::RBAC_PERM_COMMAND_LFG_GROUP, Console::No }, + { "queue", HandleLfgQueueInfoCommand, rbac::RBAC_PERM_COMMAND_LFG_QUEUE, Console::Yes }, + { "clean", HandleLfgCleanCommand, rbac::RBAC_PERM_COMMAND_LFG_CLEAN, Console::Yes }, + { "options", HandleLfgOptionsCommand, rbac::RBAC_PERM_COMMAND_LFG_OPTIONS, Console::Yes }, + { "cooldown", HandleLfgCooldownClearCommand, rbac::RBAC_PERM_COMMAND_LFG_COOLDOWN, Console::Yes }, }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp index 84b75bd1a..c098a7e30 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -26,6 +26,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "SpellAuraEffects.h" using namespace Acore::ChatCommands; @@ -39,18 +40,18 @@ public: { static ChatCommandTable listAurasCommandTable = { - { "", HandleListAllAurasCommand, SEC_MODERATOR, Console::No }, - { "id", HandleListAurasByIdCommand, SEC_MODERATOR, Console::No }, - { "name", HandleListAurasByNameCommand, SEC_MODERATOR, Console::No }, + { "", HandleListAllAurasCommand, rbac::RBAC_PERM_COMMAND_LIST_AURAS, Console::No }, + { "id", HandleListAurasByIdCommand, rbac::RBAC_PERM_COMMAND_LIST_AURAS, Console::No }, + { "name", HandleListAurasByNameCommand, rbac::RBAC_PERM_COMMAND_LIST_AURAS, Console::No }, }; static ChatCommandTable listCommandTable = { - { "creature", HandleListCreatureCommand, SEC_MODERATOR, Console::Yes }, - { "item", HandleListItemCommand, SEC_MODERATOR, Console::Yes }, - { "object", HandleListObjectCommand, SEC_MODERATOR, Console::Yes }, - { "auras", listAurasCommandTable }, - { "respawns", HandleListRespawnsCommand, SEC_GAMEMASTER, Console::No }, + { "creature", HandleListCreatureCommand, rbac::RBAC_PERM_COMMAND_LIST_CREATURE, Console::Yes }, + { "item", HandleListItemCommand, rbac::RBAC_PERM_COMMAND_LIST_ITEM, Console::Yes }, + { "object", HandleListObjectCommand, rbac::RBAC_PERM_COMMAND_LIST_OBJECT, Console::Yes }, + { "auras", listAurasCommandTable }, + { "respawns", HandleListRespawnsCommand, rbac::RBAC_PERM_COMMAND_LIST_CREATURE, Console::No }, }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 5dd54c3eb..4fb3c66ab 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -22,6 +22,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "SharedDefines.h" #include "SpellInfo.h" @@ -38,29 +39,29 @@ public: { static ChatCommandTable lookupPlayerCommandTable = { - { "ip", HandleLookupPlayerIpCommand, SEC_GAMEMASTER, Console::Yes }, - { "account", HandleLookupPlayerAccountCommand, SEC_GAMEMASTER, Console::Yes }, - { "email", HandleLookupPlayerEmailCommand, SEC_GAMEMASTER, Console::Yes } + { "ip", HandleLookupPlayerIpCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_PLAYER_IP, Console::Yes }, + { "account", HandleLookupPlayerAccountCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_PLAYER_ACCOUNT, Console::Yes }, + { "email", HandleLookupPlayerEmailCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_PLAYER_EMAIL, Console::Yes } }; static ChatCommandTable lookupCommandTable = { - { "area", HandleLookupAreaCommand, SEC_MODERATOR, Console::Yes }, - { "creature", HandleLookupCreatureCommand, SEC_MODERATOR, Console::Yes }, - { "event", HandleLookupEventCommand, SEC_MODERATOR, Console::Yes }, - { "faction", HandleLookupFactionCommand, SEC_MODERATOR, Console::Yes }, - { "item", HandleLookupItemCommand, SEC_MODERATOR, Console::Yes }, - { "item set", HandleLookupItemSetCommand, SEC_MODERATOR, Console::Yes }, - { "map", HandleLookupMapCommand, SEC_MODERATOR, Console::Yes }, - { "object", HandleLookupObjectCommand, SEC_MODERATOR, Console::Yes }, - { "gobject", HandleLookupObjectCommand, SEC_MODERATOR, Console::Yes }, - { "quest", HandleLookupQuestCommand, SEC_MODERATOR, Console::Yes }, - { "skill", HandleLookupSkillCommand, SEC_MODERATOR, Console::Yes }, - { "taxinode", HandleLookupTaxiNodeCommand, SEC_MODERATOR, Console::Yes }, - { "teleport", HandleLookupTeleCommand, SEC_MODERATOR, Console::Yes }, - { "title", HandleLookupTitleCommand, SEC_MODERATOR, Console::Yes }, - { "spell", HandleLookupSpellCommand, SEC_MODERATOR, Console::Yes }, - { "spell id", HandleLookupSpellIdCommand, SEC_MODERATOR, Console::Yes }, + { "area", HandleLookupAreaCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_AREA, Console::Yes }, + { "creature", HandleLookupCreatureCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_CREATURE, Console::Yes }, + { "event", HandleLookupEventCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_EVENT, Console::Yes }, + { "faction", HandleLookupFactionCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_FACTION, Console::Yes }, + { "item", HandleLookupItemCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_ITEM, Console::Yes }, + { "item set", HandleLookupItemSetCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_ITEMSET, Console::Yes }, + { "map", HandleLookupMapCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_MAP, Console::Yes }, + { "object", HandleLookupObjectCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_OBJECT, Console::Yes }, + { "gobject", HandleLookupObjectCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_OBJECT, Console::Yes }, + { "quest", HandleLookupQuestCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_QUEST, Console::Yes }, + { "skill", HandleLookupSkillCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_SKILL, Console::Yes }, + { "taxinode", HandleLookupTaxiNodeCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_TAXINODE, Console::Yes }, + { "teleport", HandleLookupTeleCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_TELE, Console::Yes }, + { "title", HandleLookupTitleCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_TITLE, Console::Yes }, + { "spell", HandleLookupSpellCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_SPELL, Console::Yes }, + { "spell id", HandleLookupSpellIdCommand, rbac::RBAC_PERM_COMMAND_LOOKUP_SPELL_ID, Console::Yes }, { "player", lookupPlayerCommandTable }, }; diff --git a/src/server/scripts/Commands/cs_message.cpp b/src/server/scripts/Commands/cs_message.cpp index b6f051ee8..d03d72e20 100644 --- a/src/server/scripts/Commands/cs_message.cpp +++ b/src/server/scripts/Commands/cs_message.cpp @@ -23,6 +23,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "World.h" #include "WorldSession.h" #include "WorldSessionMgr.h" @@ -38,13 +39,13 @@ public: { static ChatCommandTable commandTable = { - { "nameannounce", HandleNameAnnounceCommand, SEC_GAMEMASTER, Console::Yes }, - { "gmnameannounce", HandleGMNameAnnounceCommand, SEC_GAMEMASTER, Console::Yes }, - { "announce", HandleAnnounceCommand, SEC_GAMEMASTER, Console::Yes }, - { "gmannounce", HandleGMAnnounceCommand, SEC_GAMEMASTER, Console::Yes }, - { "notify", HandleNotifyCommand, SEC_GAMEMASTER, Console::Yes }, - { "gmnotify", HandleGMNotifyCommand, SEC_GAMEMASTER, Console::Yes }, - { "whispers", HandleWhispersCommand, SEC_MODERATOR, Console::No }, + { "nameannounce", HandleNameAnnounceCommand, rbac::RBAC_PERM_COMMAND_NAMEANNOUNCE, Console::Yes }, + { "gmnameannounce", HandleGMNameAnnounceCommand, rbac::RBAC_PERM_COMMAND_GMNAMEANNOUNCE, Console::Yes }, + { "announce", HandleAnnounceCommand, rbac::RBAC_PERM_COMMAND_ANNOUNCE, Console::Yes }, + { "gmannounce", HandleGMAnnounceCommand, rbac::RBAC_PERM_COMMAND_GMANNOUNCE, Console::Yes }, + { "notify", HandleNotifyCommand, rbac::RBAC_PERM_COMMAND_NOTIFY, Console::Yes }, + { "gmnotify", HandleGMNotifyCommand, rbac::RBAC_PERM_COMMAND_GMNOTIFY, Console::Yes }, + { "whispers", HandleWhispersCommand, rbac::RBAC_PERM_COMMAND_WHISPERS, Console::No }, }; return commandTable; } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index c28a5de5c..961e9a5b9 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -41,6 +41,7 @@ #include "Pet.h" #include "Player.h" #include "PoolMgr.h" +#include "RBAC.h" #include "Realm.h" #include "ScriptMgr.h" #include "SpellAuras.h" @@ -137,66 +138,66 @@ public: { static ChatCommandTable auraCommandTable = { - { "stack", HandleAuraStacksCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleAuraCommand, SEC_GAMEMASTER, Console::No } + { "stack", HandleAuraStacksCommand, rbac::RBAC_PERM_COMMAND_AURA_STACK, Console::No }, + { "", HandleAuraCommand, rbac::RBAC_PERM_COMMAND_AURA, Console::No } }; static ChatCommandTable commandTable = { - { "commentator", HandleCommentatorCommand, SEC_MODERATOR, Console::No }, - { "dev", HandleDevCommand, SEC_ADMINISTRATOR, Console::No }, - { "gps", HandleGPSCommand, SEC_MODERATOR, Console::No }, - { "aura", auraCommandTable }, - { "unaura", HandleUnAuraCommand, SEC_GAMEMASTER, Console::No }, - { "appear", HandleAppearCommand, SEC_MODERATOR, Console::No }, - { "summon", HandleSummonCommand, SEC_GAMEMASTER, Console::No }, - { "groupsummon", HandleGroupSummonCommand, SEC_GAMEMASTER, Console::No }, - { "commands", HandleCommandsCommand, SEC_PLAYER, Console::Yes }, - { "die", HandleDieCommand, SEC_GAMEMASTER, Console::No }, - { "revive", HandleReviveCommand, SEC_GAMEMASTER, Console::Yes }, - { "dismount", HandleDismountCommand, SEC_PLAYER, Console::No }, - { "guid", HandleGUIDCommand, SEC_GAMEMASTER, Console::No }, - { "help", HandleHelpCommand, SEC_PLAYER, Console::Yes }, - { "cooldown", HandleCooldownCommand, SEC_GAMEMASTER, Console::No }, - { "distance", HandleGetDistanceCommand, SEC_ADMINISTRATOR, Console::No }, - { "recall", HandleRecallCommand, SEC_GAMEMASTER, Console::No }, - { "save", HandleSaveCommand, SEC_PLAYER, Console::No }, - { "saveall", HandleSaveAllCommand, SEC_GAMEMASTER, Console::Yes }, - { "kick", HandleKickPlayerCommand, SEC_GAMEMASTER, Console::Yes }, - { "unstuck", HandleUnstuckCommand, SEC_GAMEMASTER, Console::Yes }, - { "linkgrave", HandleLinkGraveCommand, SEC_ADMINISTRATOR, Console::No }, - { "neargrave", HandleNearGraveCommand, SEC_GAMEMASTER, Console::No }, - { "showarea", HandleShowAreaCommand, SEC_GAMEMASTER, Console::No }, - { "hidearea", HandleHideAreaCommand, SEC_ADMINISTRATOR, Console::No }, - { "additem", HandleAddItemCommand, SEC_GAMEMASTER, Console::Yes }, - { "additem set", HandleAddItemSetCommand, SEC_GAMEMASTER, Console::No }, - { "wchange", HandleChangeWeather, SEC_ADMINISTRATOR, Console::No }, - { "maxskill", HandleMaxSkillCommand, SEC_GAMEMASTER, Console::No }, - { "setskill", HandleSetSkillCommand, SEC_GAMEMASTER, Console::No }, - { "pinfo", HandlePInfoCommand, SEC_GAMEMASTER, Console::Yes }, - { "respawn", HandleRespawnCommand, SEC_GAMEMASTER, Console::No }, - { "respawn all", HandleRespawnAllCommand, SEC_GAMEMASTER, Console::No }, - { "mute", HandleMuteCommand, SEC_GAMEMASTER, Console::Yes }, - { "mutehistory", HandleMuteInfoCommand, SEC_GAMEMASTER, Console::Yes }, - { "unmute", HandleUnmuteCommand, SEC_GAMEMASTER, Console::Yes }, - { "movegens", HandleMovegensCommand, SEC_ADMINISTRATOR, Console::No }, - { "cometome", HandleComeToMeCommand, SEC_ADMINISTRATOR, Console::No }, - { "damage", HandleDamageCommand, SEC_GAMEMASTER, Console::No }, - { "combatstop", HandleCombatStopCommand, SEC_GAMEMASTER, Console::Yes }, - { "flusharenapoints", HandleFlushArenaPointsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "freeze", HandleFreezeCommand, SEC_GAMEMASTER, Console::No }, - { "unfreeze", HandleUnFreezeCommand, SEC_GAMEMASTER, Console::No }, - { "possess", HandlePossessCommand, SEC_GAMEMASTER, Console::No }, - { "unpossess", HandleUnPossessCommand, SEC_GAMEMASTER, Console::No }, - { "bindsight", HandleBindSightCommand, SEC_ADMINISTRATOR, Console::No }, - { "unbindsight", HandleUnbindSightCommand, SEC_ADMINISTRATOR, Console::No }, - { "playall", HandlePlayAllCommand, SEC_GAMEMASTER, Console::No }, - { "skirmish", HandleSkirmishCommand, SEC_ADMINISTRATOR, Console::No }, - { "mailbox", HandleMailBoxCommand, SEC_MODERATOR, Console::No }, - { "string", HandleStringCommand, SEC_GAMEMASTER, Console::No }, - { "opendoor", HandleOpenDoorCommand, SEC_GAMEMASTER, Console::No }, - { "bm", HandleBMCommand, SEC_GAMEMASTER, Console::No }, - { "packetlog", HandlePacketLog, SEC_GAMEMASTER, Console::Yes } + { "commentator", HandleCommentatorCommand, rbac::RBAC_PERM_COMMAND_COMMENTATOR, Console::No }, + { "dev", HandleDevCommand, rbac::RBAC_PERM_COMMAND_DEV, Console::No }, + { "gps", HandleGPSCommand, rbac::RBAC_PERM_COMMAND_GPS, Console::No }, + { "aura", auraCommandTable }, + { "unaura", HandleUnAuraCommand, rbac::RBAC_PERM_COMMAND_UNAURA, Console::No }, + { "appear", HandleAppearCommand, rbac::RBAC_PERM_COMMAND_APPEAR, Console::No }, + { "summon", HandleSummonCommand, rbac::RBAC_PERM_COMMAND_SUMMON, Console::No }, + { "groupsummon", HandleGroupSummonCommand, rbac::RBAC_PERM_COMMAND_GROUP_SUMMON, Console::No }, + { "commands", HandleCommandsCommand, rbac::RBAC_PERM_COMMAND_COMMANDS, Console::Yes }, + { "die", HandleDieCommand, rbac::RBAC_PERM_COMMAND_DIE, Console::No }, + { "revive", HandleReviveCommand, rbac::RBAC_PERM_COMMAND_REVIVE, Console::Yes }, + { "dismount", HandleDismountCommand, rbac::RBAC_PERM_COMMAND_DISMOUNT, Console::No }, + { "guid", HandleGUIDCommand, rbac::RBAC_PERM_COMMAND_GUID, Console::No }, + { "help", HandleHelpCommand, rbac::RBAC_PERM_COMMAND_HELP, Console::Yes }, + { "cooldown", HandleCooldownCommand, rbac::RBAC_PERM_COMMAND_COOLDOWN, Console::No }, + { "distance", HandleGetDistanceCommand, rbac::RBAC_PERM_COMMAND_DISTANCE, Console::No }, + { "recall", HandleRecallCommand, rbac::RBAC_PERM_COMMAND_RECALL, Console::No }, + { "save", HandleSaveCommand, rbac::RBAC_PERM_COMMAND_SAVE, Console::No }, + { "saveall", HandleSaveAllCommand, rbac::RBAC_PERM_COMMAND_SAVEALL, Console::Yes }, + { "kick", HandleKickPlayerCommand, rbac::RBAC_PERM_COMMAND_KICK, Console::Yes }, + { "unstuck", HandleUnstuckCommand, rbac::RBAC_PERM_COMMAND_UNSTUCK, Console::Yes }, + { "linkgrave", HandleLinkGraveCommand, rbac::RBAC_PERM_COMMAND_LINKGRAVE, Console::No }, + { "neargrave", HandleNearGraveCommand, rbac::RBAC_PERM_COMMAND_NEARGRAVE, Console::No }, + { "showarea", HandleShowAreaCommand, rbac::RBAC_PERM_COMMAND_SHOWAREA, Console::No }, + { "hidearea", HandleHideAreaCommand, rbac::RBAC_PERM_COMMAND_HIDEAREA, Console::No }, + { "additem", HandleAddItemCommand, rbac::RBAC_PERM_COMMAND_ADDITEM, Console::Yes }, + { "additem set", HandleAddItemSetCommand, rbac::RBAC_PERM_COMMAND_ADDITEMSET, Console::No }, + { "wchange", HandleChangeWeather, rbac::RBAC_PERM_COMMAND_WCHANGE, Console::No }, + { "maxskill", HandleMaxSkillCommand, rbac::RBAC_PERM_COMMAND_MAXSKILL, Console::No }, + { "setskill", HandleSetSkillCommand, rbac::RBAC_PERM_COMMAND_SETSKILL, Console::No }, + { "pinfo", HandlePInfoCommand, rbac::RBAC_PERM_COMMAND_PINFO, Console::Yes }, + { "respawn", HandleRespawnCommand, rbac::RBAC_PERM_COMMAND_RESPAWN, Console::No }, + { "respawn all", HandleRespawnAllCommand, rbac::RBAC_PERM_COMMAND_RESPAWN_ALL, Console::No }, + { "mute", HandleMuteCommand, rbac::RBAC_PERM_COMMAND_MUTE, Console::Yes }, + { "mutehistory", HandleMuteInfoCommand, rbac::RBAC_PERM_COMMAND_MUTEHISTORY, Console::Yes }, + { "unmute", HandleUnmuteCommand, rbac::RBAC_PERM_COMMAND_UNMUTE, Console::Yes }, + { "movegens", HandleMovegensCommand, rbac::RBAC_PERM_COMMAND_MOVEGENS, Console::No }, + { "cometome", HandleComeToMeCommand, rbac::RBAC_PERM_COMMAND_COMETOME, Console::No }, + { "damage", HandleDamageCommand, rbac::RBAC_PERM_COMMAND_DAMAGE, Console::No }, + { "combatstop", HandleCombatStopCommand, rbac::RBAC_PERM_COMMAND_COMBATSTOP, Console::Yes }, + { "flusharenapoints", HandleFlushArenaPointsCommand, rbac::RBAC_PERM_COMMAND_FLUSHARENAPOINTS, Console::Yes }, + { "freeze", HandleFreezeCommand, rbac::RBAC_PERM_COMMAND_FREEZE, Console::No }, + { "unfreeze", HandleUnFreezeCommand, rbac::RBAC_PERM_COMMAND_UNFREEZE, Console::No }, + { "possess", HandlePossessCommand, rbac::RBAC_PERM_COMMAND_POSSESS, Console::No }, + { "unpossess", HandleUnPossessCommand, rbac::RBAC_PERM_COMMAND_UNPOSSESS, Console::No }, + { "bindsight", HandleBindSightCommand, rbac::RBAC_PERM_COMMAND_BINDSIGHT, Console::No }, + { "unbindsight", HandleUnbindSightCommand, rbac::RBAC_PERM_COMMAND_UNBINDSIGHT, Console::No }, + { "playall", HandlePlayAllCommand, rbac::RBAC_PERM_COMMAND_PLAYALL, Console::No }, + { "skirmish", HandleSkirmishCommand, rbac::RBAC_PERM_COMMAND_SKIRMISH, Console::No }, + { "mailbox", HandleMailBoxCommand, rbac::RBAC_PERM_COMMAND_MAILBOX, Console::No }, + { "string", HandleStringCommand, rbac::RBAC_PERM_COMMAND_STRING, Console::No }, + { "opendoor", HandleOpenDoorCommand, rbac::RBAC_PERM_COMMAND_OPENDOOR, Console::No }, + { "bm", HandleBMCommand, rbac::RBAC_PERM_COMMAND_BEASTMASTER, Console::No }, + { "packetlog", HandlePacketLog, rbac::RBAC_PERM_COMMAND_PACKETLOG, Console::Yes } }; return commandTable; @@ -1397,7 +1398,7 @@ public: Player* player = handler->GetSession()->GetPlayer(); // save GM account without delay and output message - if (handler->GetSession()->GetSecurity() >= SEC_GAMEMASTER) + if (handler->GetSession()->HasPermission(rbac::RBAC_PERM_COMMANDS_SAVE_WITHOUT_DELAY)) { if (Player* target = handler->getSelectedPlayer()) { diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index 91a164a11..88cd0cd51 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -32,6 +32,7 @@ #include "Map.h" #include "PathGenerator.h" #include "Player.h" +#include "RBAC.h" #include "TargetedMovementGenerator.h" using namespace Acore::ChatCommands; @@ -45,11 +46,11 @@ public: { static ChatCommandTable mmapCommandTable = { - { "loadedtiles", HandleMmapLoadedTilesCommand, SEC_ADMINISTRATOR, Console::No }, - { "loc", HandleMmapLocCommand, SEC_ADMINISTRATOR, Console::No }, - { "path", HandleMmapPathCommand, SEC_ADMINISTRATOR, Console::No }, - { "stats", HandleMmapStatsCommand, SEC_ADMINISTRATOR, Console::No }, - { "testarea", HandleMmapTestArea, SEC_ADMINISTRATOR, Console::No } + { "loadedtiles", HandleMmapLoadedTilesCommand, rbac::RBAC_PERM_COMMAND_MMAP_LOADEDTILES, Console::No }, + { "loc", HandleMmapLocCommand, rbac::RBAC_PERM_COMMAND_MMAP_LOC, Console::No }, + { "path", HandleMmapPathCommand, rbac::RBAC_PERM_COMMAND_MMAP_PATH, Console::No }, + { "stats", HandleMmapStatsCommand, rbac::RBAC_PERM_COMMAND_MMAP_STATS, Console::No }, + { "testarea", HandleMmapTestArea, rbac::RBAC_PERM_COMMAND_MMAP_TESTAREA, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index c2b2f6d80..058ca793e 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -21,6 +21,7 @@ #include "Opcodes.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "ReputationMgr.h" #include "StringConvert.h" @@ -35,43 +36,43 @@ public: { static ChatCommandTable modifyspeedCommandTable = { - { "fly", HandleModifyFlyCommand, SEC_GAMEMASTER, Console::No }, - { "all", HandleModifyASpeedCommand, SEC_GAMEMASTER, Console::No }, - { "walk", HandleModifySpeedCommand, SEC_GAMEMASTER, Console::No }, - { "backwalk", HandleModifyBWalkCommand, SEC_GAMEMASTER, Console::No }, - { "swim", HandleModifySwimCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleModifyASpeedCommand, SEC_GAMEMASTER, Console::No } + { "fly", HandleModifyFlyCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED_FLY, Console::No }, + { "all", HandleModifyASpeedCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED_ALL, Console::No }, + { "walk", HandleModifySpeedCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED_WALK, Console::No }, + { "backwalk", HandleModifyBWalkCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED_BACKWALK, Console::No }, + { "swim", HandleModifySwimCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED_SWIM, Console::No }, + { "", HandleModifyASpeedCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPEED, Console::No } }; static ChatCommandTable modifyCommandTable = { - { "hp", HandleModifyHPCommand, SEC_GAMEMASTER, Console::No }, - { "mana", HandleModifyManaCommand, SEC_GAMEMASTER, Console::No }, - { "rage", HandleModifyRageCommand, SEC_GAMEMASTER, Console::No }, - { "runicpower", HandleModifyRunicPowerCommand, SEC_GAMEMASTER, Console::No }, - { "energy", HandleModifyEnergyCommand, SEC_GAMEMASTER, Console::No }, - { "money", HandleModifyMoneyCommand, SEC_GAMEMASTER, Console::No }, - { "scale", HandleModifyScaleCommand, SEC_GAMEMASTER, Console::No }, - { "bit", HandleModifyBitCommand, SEC_GAMEMASTER, Console::No }, - { "faction", HandleModifyFactionCommand, SEC_ADMINISTRATOR, Console::No }, - { "spell", HandleModifySpellCommand, SEC_CONSOLE, Console::No }, - { "talentpoints", HandleModifyTalentCommand, SEC_GAMEMASTER, Console::No }, - { "mount", HandleModifyMountCommand, SEC_GAMEMASTER, Console::No }, - { "honor", HandleModifyHonorCommand, SEC_GAMEMASTER, Console::No }, - { "reputation", HandleModifyRepCommand, SEC_GAMEMASTER, Console::No }, - { "arenapoints", HandleModifyArenaCommand, SEC_GAMEMASTER, Console::No }, - { "drunk", HandleModifyDrunkCommand, SEC_GAMEMASTER, Console::No }, - { "standstate", HandleModifyStandStateCommand, SEC_GAMEMASTER, Console::No }, - { "phase", HandleModifyPhaseCommand, SEC_GAMEMASTER, Console::No }, - { "gender", HandleModifyGenderCommand, SEC_GAMEMASTER, Console::No }, + { "hp", HandleModifyHPCommand, rbac::RBAC_PERM_COMMAND_MODIFY_HP, Console::No }, + { "mana", HandleModifyManaCommand, rbac::RBAC_PERM_COMMAND_MODIFY_MANA, Console::No }, + { "rage", HandleModifyRageCommand, rbac::RBAC_PERM_COMMAND_MODIFY_RAGE, Console::No }, + { "runicpower", HandleModifyRunicPowerCommand, rbac::RBAC_PERM_COMMAND_MODIFY_RUNICPOWER, Console::No }, + { "energy", HandleModifyEnergyCommand, rbac::RBAC_PERM_COMMAND_MODIFY_ENERGY, Console::No }, + { "money", HandleModifyMoneyCommand, rbac::RBAC_PERM_COMMAND_MODIFY_MONEY, Console::No }, + { "scale", HandleModifyScaleCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SCALE, Console::No }, + { "bit", HandleModifyBitCommand, rbac::RBAC_PERM_COMMAND_MODIFY_BIT, Console::No }, + { "faction", HandleModifyFactionCommand, rbac::RBAC_PERM_COMMAND_MODIFY_FACTION, Console::No }, + { "spell", HandleModifySpellCommand, rbac::RBAC_PERM_COMMAND_MODIFY_SPELL, Console::No }, + { "talentpoints", HandleModifyTalentCommand, rbac::RBAC_PERM_COMMAND_MODIFY_TALENTPOINTS, Console::No }, + { "mount", HandleModifyMountCommand, rbac::RBAC_PERM_COMMAND_MODIFY_MOUNT, Console::No }, + { "honor", HandleModifyHonorCommand, rbac::RBAC_PERM_COMMAND_MODIFY_HONOR, Console::No }, + { "reputation", HandleModifyRepCommand, rbac::RBAC_PERM_COMMAND_MODIFY_REPUTATION, Console::No }, + { "arenapoints", HandleModifyArenaCommand, rbac::RBAC_PERM_COMMAND_MODIFY_ARENAPOINTS, Console::No }, + { "drunk", HandleModifyDrunkCommand, rbac::RBAC_PERM_COMMAND_MODIFY_DRUNK, Console::No }, + { "standstate", HandleModifyStandStateCommand, rbac::RBAC_PERM_COMMAND_MODIFY_STANDSTATE, Console::No }, + { "phase", HandleModifyPhaseCommand, rbac::RBAC_PERM_COMMAND_MODIFY_PHASE, Console::No }, + { "gender", HandleModifyGenderCommand, rbac::RBAC_PERM_COMMAND_MODIFY_GENDER, Console::No }, { "speed", modifyspeedCommandTable } }; static ChatCommandTable morphCommandTable = { - { "reset", HandleMorphResetCommand, SEC_MODERATOR, Console::No }, - { "target", HandleMorphTargetCommand, SEC_MODERATOR, Console::No }, - { "mount", HandleMorphMountCommand, SEC_MODERATOR, Console::No } + { "reset", HandleMorphResetCommand, rbac::RBAC_PERM_COMMAND_DEMORPH, Console::No }, + { "target", HandleMorphTargetCommand, rbac::RBAC_PERM_COMMAND_MORPH, Console::No }, + { "mount", HandleMorphMountCommand, rbac::RBAC_PERM_COMMAND_MORPH, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 84b5f430b..594c447c0 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -29,6 +29,7 @@ #include "Pet.h" #include "Player.h" #include "PoolMgr.h" +#include "RBAC.h" #include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand #include "Transport.h" #include @@ -143,58 +144,58 @@ public: { static ChatCommandTable npcAddCommandTable = { - { "formation", HandleNpcAddFormationCommand, SEC_ADMINISTRATOR, Console::No }, - { "item", HandleNpcAddVendorItemCommand, SEC_ADMINISTRATOR, Console::No }, - { "move", HandleNpcAddMoveCommand, SEC_ADMINISTRATOR, Console::No }, - { "temp", HandleNpcAddTempSpawnCommand, SEC_ADMINISTRATOR, Console::No }, - { "", HandleNpcAddCommand, SEC_ADMINISTRATOR, Console::No } + { "formation", HandleNpcAddFormationCommand, rbac::RBAC_PERM_COMMAND_NPC_ADD_FORMATION, Console::No }, + { "item", HandleNpcAddVendorItemCommand, rbac::RBAC_PERM_COMMAND_NPC_ADD_ITEM, Console::No }, + { "move", HandleNpcAddMoveCommand, rbac::RBAC_PERM_COMMAND_NPC_ADD_MOVE, Console::No }, + { "temp", HandleNpcAddTempSpawnCommand, rbac::RBAC_PERM_COMMAND_NPC_ADD_TEMP, Console::No }, + { "", HandleNpcAddCommand, rbac::RBAC_PERM_COMMAND_NPC_ADD, Console::No } }; static ChatCommandTable npcDeleteCommandTable = { - { "item", HandleNpcDeleteVendorItemCommand, SEC_ADMINISTRATOR, Console::No }, - { "", HandleNpcDeleteCommand, SEC_ADMINISTRATOR, Console::No } + { "item", HandleNpcDeleteVendorItemCommand, rbac::RBAC_PERM_COMMAND_NPC_DELETE_ITEM, Console::No }, + { "", HandleNpcDeleteCommand, rbac::RBAC_PERM_COMMAND_NPC_DELETE, Console::No } }; static ChatCommandTable npcFollowCommandTable = { - { "stop", HandleNpcUnFollowCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleNpcFollowCommand, SEC_GAMEMASTER, Console::No } + { "stop", HandleNpcUnFollowCommand, rbac::RBAC_PERM_COMMAND_NPC_FOLLOW_STOP, Console::No }, + { "", HandleNpcFollowCommand, rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, Console::No } }; static ChatCommandTable npcFactionCommandTable = { - { "permanent", HandleNpcSetFactionIdCommand, SEC_ADMINISTRATOR, Console::No }, - { "temp", HandleNpcSetFactionTempIdCommand, SEC_ADMINISTRATOR, Console::No }, - { "original", HandleNpcSetOriginalFaction, SEC_ADMINISTRATOR, Console::No } + { "permanent", HandleNpcSetFactionIdCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_FACTIONID, Console::No }, + { "temp", HandleNpcSetFactionTempIdCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_FACTIONID, Console::No }, + { "original", HandleNpcSetOriginalFaction, rbac::RBAC_PERM_COMMAND_NPC_SET_FACTIONID, Console::No } }; static ChatCommandTable npcSetCommandTable = { - { "allowmove", HandleNpcSetAllowMovementCommand, SEC_ADMINISTRATOR, Console::No }, - { "entry", HandleNpcSetEntryCommand, SEC_ADMINISTRATOR, Console::No }, + { "allowmove", HandleNpcSetAllowMovementCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_ALLOWMOVE, Console::No }, + { "entry", HandleNpcSetEntryCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_ENTRY, Console::No }, { "faction", npcFactionCommandTable}, - { "flag", HandleNpcSetFlagCommand, SEC_ADMINISTRATOR, Console::No }, - { "level", HandleNpcSetLevelCommand, SEC_ADMINISTRATOR, Console::No }, - { "link", HandleNpcSetLinkCommand, SEC_ADMINISTRATOR, Console::No }, - { "model", HandleNpcSetModelCommand, SEC_ADMINISTRATOR, Console::No }, - { "movetype", HandleNpcSetMoveTypeCommand, SEC_ADMINISTRATOR, Console::No }, - { "phase", HandleNpcSetPhaseCommand, SEC_ADMINISTRATOR, Console::No }, - { "wanderdistance", HandleNpcSetWanderDistanceCommand, SEC_ADMINISTRATOR, Console::No }, - { "spawntime", HandleNpcSetSpawnTimeCommand, SEC_ADMINISTRATOR, Console::No }, - { "data", HandleNpcSetDataCommand, SEC_ADMINISTRATOR, Console::No } + { "flag", HandleNpcSetFlagCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_FLAG, Console::No }, + { "level", HandleNpcSetLevelCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_LEVEL, Console::No }, + { "link", HandleNpcSetLinkCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_LINK, Console::No }, + { "model", HandleNpcSetModelCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, Console::No }, + { "movetype", HandleNpcSetMoveTypeCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, Console::No }, + { "phase", HandleNpcSetPhaseCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, Console::No }, + { "wanderdistance", HandleNpcSetWanderDistanceCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, Console::No }, + { "spawntime", HandleNpcSetSpawnTimeCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, Console::No }, + { "data", HandleNpcSetDataCommand, rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, Console::No } }; static ChatCommandTable npcCommandTable = { - { "info", HandleNpcInfoCommand, SEC_GAMEMASTER, Console::No }, - { "guid", HandleNpcGuidCommand, SEC_GAMEMASTER, Console::No }, - { "near", HandleNpcNearCommand, SEC_GAMEMASTER, Console::No }, - { "move", HandleNpcMoveCommand, SEC_GAMEMASTER, Console::No }, - { "playemote", HandleNpcPlayEmoteCommand, SEC_GAMEMASTER, Console::No }, - { "say", HandleNpcSayCommand, SEC_GAMEMASTER, Console::No }, - { "textemote", HandleNpcTextEmoteCommand, SEC_GAMEMASTER, Console::No }, - { "whisper", HandleNpcWhisperCommand, SEC_GAMEMASTER, Console::No }, - { "yell", HandleNpcYellCommand, SEC_GAMEMASTER, Console::No }, - { "tame", HandleNpcTameCommand, SEC_GAMEMASTER, Console::No }, - { "do", HandleNpcDoActionCommand, SEC_GAMEMASTER, Console::No }, + { "info", HandleNpcInfoCommand, rbac::RBAC_PERM_COMMAND_NPC_INFO, Console::No }, + { "guid", HandleNpcGuidCommand, rbac::RBAC_PERM_COMMAND_NPC_INFO, Console::No }, + { "near", HandleNpcNearCommand, rbac::RBAC_PERM_COMMAND_NPC_NEAR, Console::No }, + { "move", HandleNpcMoveCommand, rbac::RBAC_PERM_COMMAND_NPC_MOVE, Console::No }, + { "playemote", HandleNpcPlayEmoteCommand, rbac::RBAC_PERM_COMMAND_NPC_PLAYEMOTE, Console::No }, + { "say", HandleNpcSayCommand, rbac::RBAC_PERM_COMMAND_NPC_SAY, Console::No }, + { "textemote", HandleNpcTextEmoteCommand, rbac::RBAC_PERM_COMMAND_NPC_TEXTEMOTE, Console::No }, + { "whisper", HandleNpcWhisperCommand, rbac::RBAC_PERM_COMMAND_NPC_WHISPER, Console::No }, + { "yell", HandleNpcYellCommand, rbac::RBAC_PERM_COMMAND_NPC_YELL, Console::No }, + { "tame", HandleNpcTameCommand, rbac::RBAC_PERM_COMMAND_NPC_TAME, Console::No }, + { "do", HandleNpcDoActionCommand, rbac::RBAC_PERM_COMMAND_NPC_EVADE, Console::No }, { "add", npcAddCommandTable }, { "delete", npcDeleteCommandTable }, { "follow", npcFollowCommandTable }, diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp index d2c8d5b1d..42137e367 100644 --- a/src/server/scripts/Commands/cs_pet.cpp +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -22,6 +22,7 @@ #include "ObjectMgr.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "SpellInfo.h" #include "SpellMgr.h" @@ -36,9 +37,9 @@ public: { static ChatCommandTable petCommandTable = { - { "create", HandlePetCreateCommand, SEC_GAMEMASTER, Console::No }, - { "learn", HandlePetLearnCommand, SEC_GAMEMASTER, Console::No }, - { "unlearn", HandlePetUnlearnCommand, SEC_GAMEMASTER, Console::No } + { "create", HandlePetCreateCommand, rbac::RBAC_PERM_COMMAND_PET_CREATE, Console::No }, + { "learn", HandlePetLearnCommand, rbac::RBAC_PERM_COMMAND_PET_LEARN, Console::No }, + { "unlearn", HandlePetUnlearnCommand, rbac::RBAC_PERM_COMMAND_PET_UNLEARN, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_player.cpp b/src/server/scripts/Commands/cs_player.cpp index 240db01a0..a0eb7e9ec 100644 --- a/src/server/scripts/Commands/cs_player.cpp +++ b/src/server/scripts/Commands/cs_player.cpp @@ -17,6 +17,7 @@ #include "CommandScript.h" #include "PlayerCommand.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -29,8 +30,8 @@ public: { static ChatCommandTable playerCommandTable = { - { "learn", HandlePlayerLearnCommand, SEC_GAMEMASTER, Console::Yes }, - { "unlearn", HandlePlayerUnLearnCommand, SEC_GAMEMASTER, Console::Yes } + { "learn", HandlePlayerLearnCommand, rbac::RBAC_PERM_COMMAND_LEARN, Console::Yes }, + { "unlearn", HandlePlayerUnLearnCommand, rbac::RBAC_PERM_COMMAND_UNLEARN, Console::Yes } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_player_settings.cpp b/src/server/scripts/Commands/cs_player_settings.cpp index 06f038b91..30aadef1b 100644 --- a/src/server/scripts/Commands/cs_player_settings.cpp +++ b/src/server/scripts/Commands/cs_player_settings.cpp @@ -19,6 +19,7 @@ #include "CommandScript.h" #include "Player.h" #include "PlayerSettings.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -31,7 +32,7 @@ public: { static ChatCommandTable playerSettingsCommandTable = { - { "announcer", HandleSettingsAnnouncerFlags, SEC_MODERATOR, Console::No }, + { "announcer", HandleSettingsAnnouncerFlags, rbac::RBAC_PERM_COMMAND_SETTINGS_ANNOUNCER, Console::No }, }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_pooltools.cpp b/src/server/scripts/Commands/cs_pooltools.cpp index a915d8156..db641a76a 100644 --- a/src/server/scripts/Commands/cs_pooltools.cpp +++ b/src/server/scripts/Commands/cs_pooltools.cpp @@ -25,6 +25,7 @@ #include "GridNotifiersImpl.h" #include "MapMgr.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "Tokenize.h" @@ -63,12 +64,12 @@ public: { static ChatCommandTable poolToolsCommandTable = { - { "start", HandlePoolStart, SEC_ADMINISTRATOR, Console::No }, - { "def", HandlePoolDef, SEC_ADMINISTRATOR, Console::No }, - { "add", HandlePoolAdd, SEC_ADMINISTRATOR, Console::No }, - { "remove", HandlePoolRemove, SEC_ADMINISTRATOR, Console::No }, - { "end", HandlePoolEnd, SEC_ADMINISTRATOR, Console::No }, - { "clear", HandlePoolClear, SEC_ADMINISTRATOR, Console::No } + { "start", HandlePoolStart, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "def", HandlePoolDef, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "add", HandlePoolAdd, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "remove", HandlePoolRemove, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "end", HandlePoolEnd, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No }, + { "clear", HandlePoolClear, rbac::RBAC_PERM_COMMAND_DEBUG, Console::No } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index daee0c91c..bc1faf49b 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -22,6 +22,7 @@ #include "GameTime.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "ReputationMgr.h" using namespace Acore::ChatCommands; @@ -35,11 +36,11 @@ public: { static ChatCommandTable questCommandTable = { - { "add", HandleQuestAdd, SEC_GAMEMASTER, Console::Yes }, - { "complete", HandleQuestComplete, SEC_GAMEMASTER, Console::Yes }, - { "remove", HandleQuestRemove, SEC_GAMEMASTER, Console::Yes }, - { "reward", HandleQuestReward, SEC_GAMEMASTER, Console::Yes }, - { "status", HandleQuestStatus, SEC_GAMEMASTER, Console::Yes }, + { "add", HandleQuestAdd, rbac::RBAC_PERM_COMMAND_QUEST_ADD, Console::Yes }, + { "complete", HandleQuestComplete, rbac::RBAC_PERM_COMMAND_QUEST_COMPLETE, Console::Yes }, + { "remove", HandleQuestRemove, rbac::RBAC_PERM_COMMAND_QUEST_REMOVE, Console::Yes }, + { "reward", HandleQuestReward, rbac::RBAC_PERM_COMMAND_QUEST_REWARD, Console::Yes }, + { "status", HandleQuestStatus, rbac::RBAC_PERM_COMMAND_QUEST, Console::Yes }, }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp new file mode 100644 index 000000000..7d80a33a7 --- /dev/null +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -0,0 +1,289 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "AccountMgr.h" +#include "Chat.h" +#include "CommandScript.h" +#include "Language.h" +#include "Player.h" +#include "RBAC.h" +#include "Realm.h" +#include "ScriptMgr.h" +#include "World.h" +#include "WorldSession.h" +#include "WorldSessionMgr.h" + +struct RBACCommandData +{ + RBACCommandData(rbac::RBACData* rbac_, bool needDelete_) : rbac(rbac_), needDelete(needDelete_) { } + RBACCommandData(RBACCommandData const&) = delete; + ~RBACCommandData() + { + if (needDelete) + delete rbac; + } + + rbac::RBACData* rbac = nullptr; + bool needDelete = false; +}; + +using namespace Acore::ChatCommands; + +class rbac_commandscript : public CommandScript +{ +public: + rbac_commandscript() : CommandScript("rbac_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable rbacAccountCommandTable = + { + { "list", HandleRBACPermListCommand, LANG_RBAC_HELP_ACC_LIST, rbac::RBAC_PERM_COMMAND_RBAC_ACC_PERM_LIST, Console::Yes }, + { "grant", HandleRBACPermGrantCommand, LANG_RBAC_HELP_ACC_GRANT, rbac::RBAC_PERM_COMMAND_RBAC_ACC_PERM_GRANT, Console::Yes }, + { "deny", HandleRBACPermDenyCommand, LANG_RBAC_HELP_ACC_DENY, rbac::RBAC_PERM_COMMAND_RBAC_ACC_PERM_DENY, Console::Yes }, + { "revoke", HandleRBACPermRevokeCommand, LANG_RBAC_HELP_ACC_REVOKE, rbac::RBAC_PERM_COMMAND_RBAC_ACC_PERM_REVOKE, Console::Yes }, + }; + + static ChatCommandTable rbacCommandTable = + { + { "account", rbacAccountCommandTable }, + { "list", HandleRBACListPermissionsCommand, rbac::RBAC_PERM_COMMAND_RBAC_LIST, Console::Yes }, + }; + + static ChatCommandTable commandTable = + { + { "rbac", rbacCommandTable }, + }; + + return commandTable; + } + + static RBACCommandData GetRBACData(uint32 accountId, std::string const& accountName) + { + if (WorldSession* session = sWorldSessionMgr->FindSession(accountId)) + return { session->GetRBACData(), false }; + + rbac::RBACData* rbac = new rbac::RBACData(accountId, accountName, realm.Id.Realm, AccountMgr::GetSecurity(accountId, realm.Id.Realm)); + rbac->LoadFromDB(); + + return { rbac, true }; + } + + static bool HandleRBACPermGrantCommand(ChatHandler* handler, AccountIdentifier account, uint32 permId, Optional realmId) + { + if (handler->HasLowerSecurityAccount(nullptr, account.GetID(), true)) + return false; + + if (!realmId) + realmId = -1; + + RBACCommandData data = GetRBACData(account.GetID(), account.GetName()); + + rbac::RBACCommandResult result = data.rbac->GrantPermission(permId, *realmId); + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(permId); + + switch (result) + { + case rbac::RBAC_CANT_ADD_ALREADY_ADDED: + handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_LIST, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_IN_DENIED_LIST: + handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_OK: + handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_ID_DOES_NOT_EXISTS: + handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, permId); + break; + default: + break; + } + + return true; + } + + static bool HandleRBACPermDenyCommand(ChatHandler* handler, AccountIdentifier account, uint32 permId, Optional realmId) + { + if (handler->HasLowerSecurityAccount(nullptr, account.GetID(), true)) + return false; + + if (!realmId) + realmId = -1; + + RBACCommandData data = GetRBACData(account.GetID(), account.GetName()); + + rbac::RBACCommandResult result = data.rbac->DenyPermission(permId, *realmId); + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(permId); + + switch (result) + { + case rbac::RBAC_CANT_ADD_ALREADY_ADDED: + handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_LIST, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_IN_GRANTED_LIST: + handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_OK: + handler->PSendSysMessage(LANG_RBAC_PERM_DENIED, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_ID_DOES_NOT_EXISTS: + handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, permId); + break; + default: + break; + } + + return true; + } + + static bool HandleRBACPermRevokeCommand(ChatHandler* handler, AccountIdentifier account, uint32 permId, Optional realmId) + { + if (handler->HasLowerSecurityAccount(nullptr, account.GetID(), true)) + return false; + + if (!realmId) + realmId = -1; + + RBACCommandData data = GetRBACData(account.GetID(), account.GetName()); + + rbac::RBACCommandResult result = data.rbac->RevokePermission(permId, *realmId); + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(permId); + + switch (result) + { + case rbac::RBAC_CANT_REVOKE_NOT_IN_LIST: + handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED_NOT_IN_LIST, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_OK: + handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED, permId, permission->GetName().c_str(), + *realmId, account.GetID(), account.GetName().c_str()); + break; + case rbac::RBAC_ID_DOES_NOT_EXISTS: + handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, permId); + break; + default: + break; + } + + return true; + } + + static char const* GetSecurityLevelName(uint8 secLevel) + { + switch (secLevel) + { + case SEC_PLAYER: return "SEC_PLAYER"; + case SEC_MODERATOR: return "SEC_MODERATOR"; + case SEC_GAMEMASTER: return "SEC_GAMEMASTER"; + case SEC_ADMINISTRATOR: return "SEC_ADMINISTRATOR"; + case SEC_CONSOLE: return "SEC_CONSOLE"; + default: return "Unknown"; + } + } + + static bool HandleRBACPermListCommand(ChatHandler* handler, AccountIdentifier account) + { + RBACCommandData data = GetRBACData(account.GetID(), account.GetName()); + + handler->PSendSysMessage(LANG_RBAC_LIST_HEADER_GRANTED, data.rbac->GetId(), data.rbac->GetName().c_str()); + rbac::RBACPermissionContainer const& granted = data.rbac->GetGrantedPermissions(); + if (granted.empty()) + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_EMPTY)); + else + { + for (uint32 grantedId : granted) + { + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(grantedId); + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str()); + } + } + + handler->PSendSysMessage(LANG_RBAC_LIST_HEADER_DENIED, data.rbac->GetId(), data.rbac->GetName().c_str()); + rbac::RBACPermissionContainer const& denied = data.rbac->GetDeniedPermissions(); + if (denied.empty()) + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_EMPTY)); + else + { + for (uint32 deniedId : denied) + { + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(deniedId); + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str()); + } + } + + handler->PSendSysMessage(LANG_RBAC_LIST_HEADER_BY_SEC_LEVEL, data.rbac->GetId(), data.rbac->GetName().c_str(), + data.rbac->GetSecurityLevel(), GetSecurityLevelName(data.rbac->GetSecurityLevel())); + rbac::RBACPermissionContainer const& defaultPermissions = sAccountMgr->GetRBACDefaultPermissions(data.rbac->GetSecurityLevel()); + if (defaultPermissions.empty()) + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_EMPTY)); + else + { + for (uint32 defaultPermission : defaultPermissions) + { + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(defaultPermission); + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str()); + } + } + + return true; + } + + static bool HandleRBACListPermissionsCommand(ChatHandler* handler, Optional permId) + { + if (!permId) + { + rbac::RBACPermissionsContainer const& permissions = sAccountMgr->GetRBACPermissionList(); + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_PERMISSIONS_HEADER)); + for (auto const& [_, permission] : permissions) + { + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str()); + } + } + else + { + rbac::RBACPermission const* permission = sAccountMgr->GetRBACPermission(*permId); + if (!permission) + { + handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, *permId); + handler->SetSentErrorMessage(true); + return false; + } + + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_PERMISSIONS_HEADER)); + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str()); + handler->SendSysMessage(handler->GetAcoreString(LANG_RBAC_LIST_PERMS_LINKED_HEADER)); + for (uint32 linkedPerm : permission->GetLinkedPermissions()) + if (rbac::RBACPermission const* rbacPermission = sAccountMgr->GetRBACPermission(linkedPerm)) + handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, rbacPermission->GetId(), rbacPermission->GetName().c_str()); + } + + return true; + } +}; + +void AddSC_rbac_commandscript() +{ + new rbac_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index ef121f039..ef6cf787a 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "AccountMgr.h" #include "AchievementMgr.h" #include "AuctionHouseMgr.h" #include "AutobroadcastMgr.h" @@ -31,6 +32,7 @@ #include "MotdMgr.h" #include "ObjectMgr.h" #include "PoolMgr.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "ServerMailMgr.h" #include "SkillDiscovery.h" @@ -55,122 +57,123 @@ public: { static ChatCommandTable reloadAllCommandTable = { - { "achievement", HandleReloadAllAchievementCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "area", HandleReloadAllAreaCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gossips", HandleReloadAllGossipsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item", HandleReloadAllItemCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "locales", HandleReloadAllLocalesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "loot", HandleReloadAllLootCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "npc", HandleReloadAllNpcCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest", HandleReloadAllQuestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "scripts", HandleReloadAllScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell", HandleReloadAllSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "", HandleReloadAllCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "achievement", HandleReloadAllAchievementCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_ACHIEVEMENT, Console::Yes }, + { "area", HandleReloadAllAreaCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_AREA, Console::Yes }, + { "gossips", HandleReloadAllGossipsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_GOSSIP, Console::Yes }, + { "item", HandleReloadAllItemCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_ITEM, Console::Yes }, + { "locales", HandleReloadAllLocalesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_LOCALES, Console::Yes }, + { "loot", HandleReloadAllLootCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_LOOT, Console::Yes }, + { "npc", HandleReloadAllNpcCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_NPC, Console::Yes }, + { "quest", HandleReloadAllQuestCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_QUEST, Console::Yes }, + { "scripts", HandleReloadAllScriptsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_SCRIPTS, Console::Yes }, + { "spell", HandleReloadAllSpellCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL_SPELL, Console::Yes }, + { "", HandleReloadAllCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ALL, Console::Yes }, }; static ChatCommandTable reloadCommandTable = { - { "antidos_opcode_policies", HandleReloadAntiDosOpcodePoliciesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "auctions", HandleReloadAuctionsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "dungeon_access_template", HandleReloadDungeonAccessCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "dungeon_access_requirements", HandleReloadDungeonAccessCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "achievement_criteria_data", HandleReloadAchievementCriteriaDataCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "achievement_reward", HandleReloadAchievementRewardCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "antidos_opcode_policies", HandleReloadAntiDosOpcodePoliciesCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "auctions", HandleReloadAuctionsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AUCTIONS, Console::Yes }, + { "dungeon_access_template", HandleReloadDungeonAccessCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACCESS_REQUIREMENT, Console::Yes }, + { "dungeon_access_requirements", HandleReloadDungeonAccessCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACCESS_REQUIREMENT, Console::Yes }, + { "achievement_criteria_data", HandleReloadAchievementCriteriaDataCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_CRITERIA_DATA, Console::Yes }, + { "achievement_reward", HandleReloadAchievementRewardCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD, Console::Yes }, { "all", reloadAllCommandTable }, - { "areatrigger", HandleReloadQuestAreaTriggersCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "areatrigger_involvedrelation", HandleReloadQuestAreaTriggersCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "areatrigger_tavern", HandleReloadAreaTriggerTavernCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "areatrigger_teleport", HandleReloadAreaTriggerTeleportCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "autobroadcast", HandleReloadAutobroadcastCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "motd", HandleReloadMotdCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "broadcast_text", HandleReloadBroadcastTextCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "battleground_template", HandleReloadBattlegroundTemplate, SEC_ADMINISTRATOR, Console::Yes }, - { "command", HandleReloadCommandCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "conditions", HandleReloadConditions, SEC_ADMINISTRATOR, Console::Yes }, - { "config", HandleReloadConfigCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_text", HandleReloadCreatureText, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_questender", HandleReloadCreatureQuestEnderCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_linked_respawn", HandleReloadLinkedRespawnCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_loot_template", HandleReloadLootTemplatesCreatureCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_movement_override", HandleReloadCreatureMovementOverrideCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "creature_onkill_reputation", HandleReloadOnKillReputationCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_queststarter", HandleReloadCreatureQuestStarterCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_template", HandleReloadCreatureTemplateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "disables", HandleReloadDisablesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "disenchant_loot_template", HandleReloadLootTemplatesDisenchantCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "event_scripts", HandleReloadEventScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "fishing_loot_template", HandleReloadLootTemplatesFishingCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "game_graveyard", HandleReloadGameGraveyardCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "graveyard_zone", HandleReloadGameGraveyardZoneCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "game_tele", HandleReloadGameTeleCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gameobject_questender", HandleReloadGOQuestEnderCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gameobject_loot_template", HandleReloadLootTemplatesGameobjectCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gameobject_queststarter", HandleReloadGOQuestStarterCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gm_tickets", HandleReloadGMTicketsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gossip_menu", HandleReloadGossipMenuCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gossip_menu_option", HandleReloadGossipMenuOptionCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item_enchantment_template", HandleReloadItemEnchantementsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item_loot_template", HandleReloadLootTemplatesItemCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item_set_names", HandleReloadItemSetNamesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "lfg_dungeon_rewards", HandleReloadLfgRewardsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "achievement_reward_locale", HandleReloadLocalesAchievementRewardCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_template_locale", HandleReloadLocalesCreatureCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "creature_text_locale", HandleReloadLocalesCreatureTextCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gameobject_template_locale", HandleReloadLocalesGameobjectCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gossip_menu_option_locale", HandleReloadLocalesGossipMenuOptionCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item_template_locale", HandleReloadLocalesItemCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "item_set_name_locale", HandleReloadLocalesItemSetNameCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "npc_text_locale", HandleReloadLocalesNpcTextCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "page_text_locale", HandleReloadLocalesPageTextCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "points_of_interest_locale", HandleReloadLocalesPointsOfInterestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_template_locale", HandleReloadLocalesQuestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_offer_reward_locale", HandleReloadLocalesQuestOfferRewardCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_request_item_locale", HandleReloadLocalesQuestRequestItemsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "mail_level_reward", HandleReloadMailLevelRewardCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "mail_loot_template", HandleReloadLootTemplatesMailCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "mail_server_template", HandleReloadMailServerTemplateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "milling_loot_template", HandleReloadLootTemplatesMillingCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "npc_spellclick_spells", HandleReloadSpellClickSpellsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "trainer", HandleReloadTrainerCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "npc_vendor", HandleReloadNpcVendorCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "game_event_npc_vendor", HandleReloadGameEventNPCVendorCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "page_text", HandleReloadPageTextsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "pickpocketing_loot_template", HandleReloadLootTemplatesPickpocketingCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "points_of_interest", HandleReloadPointsOfInterestCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "prospecting_loot_template", HandleReloadLootTemplatesProspectingCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_greeting", HandleReloadQuestGreetingCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_poi", HandleReloadQuestPOICommand, SEC_ADMINISTRATOR, Console::Yes }, - { "quest_template", HandleReloadQuestTemplateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "reference_loot_template", HandleReloadLootTemplatesReferenceCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "reserved_name", HandleReloadReservedNameCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "profanity_name", HandleReloadProfanityNameCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "reputation_reward_rate", HandleReloadReputationRewardRateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "reputation_spillover_template", HandleReloadReputationRewardRateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "skill_discovery_template", HandleReloadSkillDiscoveryTemplateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "skill_extra_item_template", HandleReloadSkillExtraItemTemplateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "skill_fishing_base_level", HandleReloadSkillFishingBaseLevelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "skinning_loot_template", HandleReloadLootTemplatesSkinningCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "smart_scripts", HandleReloadSmartScripts, SEC_ADMINISTRATOR, Console::Yes }, - { "spawn_group", HandleReloadSpawnGroupCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_required", HandleReloadSpellRequiredCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_area", HandleReloadSpellAreaCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_bonus_data", HandleReloadSpellBonusesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_group", HandleReloadSpellGroupsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_loot_template", HandleReloadLootTemplatesSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_linked_spell", HandleReloadSpellLinkedSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_pet_auras", HandleReloadSpellPetAurasCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_proc", HandleReloadSpellProcsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_scripts", HandleReloadSpellScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_target_position", HandleReloadSpellTargetPositionCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_threats", HandleReloadSpellThreatsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_group_stack_rules", HandleReloadSpellGroupStackRulesCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "player_loot_template", HandleReloadLootTemplatesPlayerCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "module_string", HandleReloadModuleStringCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "acore_string", HandleReloadAcoreStringCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "warden_action", HandleReloadWardenactionCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "waypoint_scripts", HandleReloadWpScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "waypoint_data", HandleReloadWpCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "vehicle_accessory", HandleReloadVehicleAccessoryCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "vehicle_template_accessory", HandleReloadVehicleTemplateAccessoryCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "areatrigger", HandleReloadQuestAreaTriggersCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_INVOLVEDRELATION, Console::Yes }, + { "areatrigger_involvedrelation", HandleReloadQuestAreaTriggersCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_INVOLVEDRELATION, Console::Yes }, + { "areatrigger_tavern", HandleReloadAreaTriggerTavernCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TAVERN, Console::Yes }, + { "areatrigger_teleport", HandleReloadAreaTriggerTeleportCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TELEPORT, Console::Yes }, + { "autobroadcast", HandleReloadAutobroadcastCommand, rbac::RBAC_PERM_COMMAND_RELOAD_AUTOBROADCAST, Console::Yes }, + { "motd", HandleReloadMotdCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "broadcast_text", HandleReloadBroadcastTextCommand, rbac::RBAC_PERM_COMMAND_RELOAD_BROADCAST_TEXT, Console::Yes }, + { "battleground_template", HandleReloadBattlegroundTemplate, rbac::RBAC_PERM_COMMAND_RELOAD_BATTLEGROUND_TEMPLATE, Console::Yes }, + { "command", HandleReloadCommandCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "conditions", HandleReloadConditions, rbac::RBAC_PERM_COMMAND_RELOAD_CONDITIONS, Console::Yes }, + { "config", HandleReloadConfigCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CONFIG, Console::Yes }, + { "creature_text", HandleReloadCreatureText, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEXT, Console::Yes }, + { "creature_questender", HandleReloadCreatureQuestEnderCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTENDER, Console::Yes }, + { "creature_linked_respawn", HandleReloadLinkedRespawnCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_LINKED_RESPAWN, Console::Yes }, + { "creature_loot_template", HandleReloadLootTemplatesCreatureCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_LOOT_TEMPLATE, Console::Yes }, + { "creature_movement_override", HandleReloadCreatureMovementOverrideCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_MOVEMENT_OVERRIDE, Console::Yes}, + { "creature_onkill_reputation", HandleReloadOnKillReputationCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_ONKILL_REPUTATION, Console::Yes }, + { "creature_queststarter", HandleReloadCreatureQuestStarterCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTSTARTER, Console::Yes }, + { "creature_template", HandleReloadCreatureTemplateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEMPLATE, Console::Yes }, + { "disables", HandleReloadDisablesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_DISABLES, Console::Yes }, + { "disenchant_loot_template", HandleReloadLootTemplatesDisenchantCommand, rbac::RBAC_PERM_COMMAND_RELOAD_DISENCHANT_LOOT_TEMPLATE, Console::Yes }, + { "event_scripts", HandleReloadEventScriptsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_EVENT_SCRIPTS, Console::Yes }, + { "fishing_loot_template", HandleReloadLootTemplatesFishingCommand, rbac::RBAC_PERM_COMMAND_RELOAD_FISHING_LOOT_TEMPLATE, Console::Yes }, + { "game_graveyard", HandleReloadGameGraveyardCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "graveyard_zone", HandleReloadGameGraveyardZoneCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GRAVEYARD_ZONE, Console::Yes }, + { "game_tele", HandleReloadGameTeleCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GAME_TELE, Console::Yes }, + { "gameobject_questender", HandleReloadGOQuestEnderCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER, Console::Yes }, + { "gameobject_loot_template", HandleReloadLootTemplatesGameobjectCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE, Console::Yes }, + { "gameobject_queststarter", HandleReloadGOQuestStarterCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER, Console::Yes }, + { "gm_tickets", HandleReloadGMTicketsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GM_TICKETS, Console::Yes }, + { "gossip_menu", HandleReloadGossipMenuCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU, Console::Yes }, + { "gossip_menu_option", HandleReloadGossipMenuOptionCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION, Console::Yes }, + { "item_enchantment_template", HandleReloadItemEnchantementsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_ENCHANTMENT_TEMPLATE, Console::Yes }, + { "item_loot_template", HandleReloadLootTemplatesItemCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_LOOT_TEMPLATE, Console::Yes }, + { "item_set_names", HandleReloadItemSetNamesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAMES, Console::Yes }, + { "lfg_dungeon_rewards", HandleReloadLfgRewardsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_LFG_DUNGEON_REWARDS, Console::Yes }, + { "achievement_reward_locale", HandleReloadLocalesAchievementRewardCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD_LOCALE, Console::Yes }, + { "creature_template_locale", HandleReloadLocalesCreatureCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEMPLATE_LOCALE, Console::Yes }, + { "creature_text_locale", HandleReloadLocalesCreatureTextCommand, rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEXT_LOCALE, Console::Yes }, + { "gameobject_template_locale", HandleReloadLocalesGameobjectCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_TEMPLATE_LOCALE, Console::Yes }, + { "gossip_menu_option_locale", HandleReloadLocalesGossipMenuOptionCommand, rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION_LOCALE, Console::Yes }, + { "item_template_locale", HandleReloadLocalesItemCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_TEMPLATE_LOCALE, Console::Yes }, + { "item_set_name_locale", HandleReloadLocalesItemSetNameCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_SET_NAME_LOCALE, Console::Yes }, + { "npc_text_locale", HandleReloadLocalesNpcTextCommand, rbac::RBAC_PERM_COMMAND_RELOAD_NPC_TEXT_LOCALE, Console::Yes }, + { "page_text_locale", HandleReloadLocalesPageTextCommand, rbac::RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT_LOCALE, Console::Yes }, + { "points_of_interest_locale", HandleReloadLocalesPointsOfInterestCommand, rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST_LOCALE, Console::Yes }, + { "quest_template_locale", HandleReloadLocalesQuestCommand, rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE_LOCALE, Console::Yes }, + { "quest_offer_reward_locale", HandleReloadLocalesQuestOfferRewardCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "quest_request_item_locale", HandleReloadLocalesQuestRequestItemsCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "mail_level_reward", HandleReloadMailLevelRewardCommand, rbac::RBAC_PERM_COMMAND_RELOAD_MAIL_LEVEL_REWARD, Console::Yes }, + { "mail_loot_template", HandleReloadLootTemplatesMailCommand, rbac::RBAC_PERM_COMMAND_RELOAD_MAIL_LOOT_TEMPLATE, Console::Yes }, + { "mail_server_template", HandleReloadMailServerTemplateCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "milling_loot_template", HandleReloadLootTemplatesMillingCommand, rbac::RBAC_PERM_COMMAND_RELOAD_MILLING_LOOT_TEMPLATE, Console::Yes }, + { "npc_spellclick_spells", HandleReloadSpellClickSpellsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_NPC_SPELLCLICK_SPELLS, Console::Yes }, + { "trainer", HandleReloadTrainerCommand, rbac::RBAC_PERM_COMMAND_RELOAD_TRAINER, Console::Yes }, + { "npc_vendor", HandleReloadNpcVendorCommand, rbac::RBAC_PERM_COMMAND_RELOAD_NPC_VENDOR, Console::Yes }, + { "game_event_npc_vendor", HandleReloadGameEventNPCVendorCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "page_text", HandleReloadPageTextsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_PAGE_TEXT, Console::Yes }, + { "pickpocketing_loot_template", HandleReloadLootTemplatesPickpocketingCommand, rbac::RBAC_PERM_COMMAND_RELOAD_PICKPOCKETING_LOOT_TEMPLATE, Console::Yes }, + { "points_of_interest", HandleReloadPointsOfInterestCommand, rbac::RBAC_PERM_COMMAND_RELOAD_POINTS_OF_INTEREST, Console::Yes }, + { "prospecting_loot_template", HandleReloadLootTemplatesProspectingCommand, rbac::RBAC_PERM_COMMAND_RELOAD_PROSPECTING_LOOT_TEMPLATE, Console::Yes }, + { "quest_greeting", HandleReloadQuestGreetingCommand, rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING, Console::Yes }, + { "quest_poi", HandleReloadQuestPOICommand, rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_POI, Console::Yes }, + { "quest_template", HandleReloadQuestTemplateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE, Console::Yes }, + { "rbac", HandleReloadRBACCommand, rbac::RBAC_PERM_COMMAND_RELOAD_RBAC, Console::Yes }, + { "reference_loot_template", HandleReloadLootTemplatesReferenceCommand, rbac::RBAC_PERM_COMMAND_RELOAD_REFERENCE_LOOT_TEMPLATE, Console::Yes }, + { "reserved_name", HandleReloadReservedNameCommand, rbac::RBAC_PERM_COMMAND_RELOAD_RESERVED_NAME, Console::Yes }, + { "profanity_name", HandleReloadProfanityNameCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "reputation_reward_rate", HandleReloadReputationRewardRateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_REPUTATION_REWARD_RATE, Console::Yes }, + { "reputation_spillover_template", HandleReloadReputationRewardRateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPILLOVER_TEMPLATE, Console::Yes }, + { "skill_discovery_template", HandleReloadSkillDiscoveryTemplateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SKILL_DISCOVERY_TEMPLATE, Console::Yes }, + { "skill_extra_item_template", HandleReloadSkillExtraItemTemplateCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SKILL_EXTRA_ITEM_TEMPLATE, Console::Yes }, + { "skill_fishing_base_level", HandleReloadSkillFishingBaseLevelCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SKILL_FISHING_BASE_LEVEL, Console::Yes }, + { "skinning_loot_template", HandleReloadLootTemplatesSkinningCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SKINNING_LOOT_TEMPLATE, Console::Yes }, + { "smart_scripts", HandleReloadSmartScripts, rbac::RBAC_PERM_COMMAND_RELOAD_SMART_SCRIPTS, Console::Yes }, + { "spawn_group", HandleReloadSpawnGroupCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "spell_required", HandleReloadSpellRequiredCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_REQUIRED, Console::Yes }, + { "spell_area", HandleReloadSpellAreaCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_AREA, Console::Yes }, + { "spell_bonus_data", HandleReloadSpellBonusesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_BONUS_DATA, Console::Yes }, + { "spell_group", HandleReloadSpellGroupsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP, Console::Yes }, + { "spell_loot_template", HandleReloadLootTemplatesSpellCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE, Console::Yes }, + { "spell_linked_spell", HandleReloadSpellLinkedSpellCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL, Console::Yes }, + { "spell_pet_auras", HandleReloadSpellPetAurasCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS, Console::Yes }, + { "spell_proc", HandleReloadSpellProcsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, Console::Yes }, + { "spell_scripts", HandleReloadSpellScriptsCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "spell_target_position", HandleReloadSpellTargetPositionCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, Console::Yes }, + { "spell_threats", HandleReloadSpellThreatsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS, Console::Yes }, + { "spell_group_stack_rules", HandleReloadSpellGroupStackRulesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES, Console::Yes }, + { "player_loot_template", HandleReloadLootTemplatesPlayerCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "module_string", HandleReloadModuleStringCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "acore_string", HandleReloadAcoreStringCommand, rbac::RBAC_PERM_COMMAND_RELOAD_ACORE_STRING, Console::Yes }, + { "warden_action", HandleReloadWardenactionCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes }, + { "waypoint_scripts", HandleReloadWpScriptsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS, Console::Yes }, + { "waypoint_data", HandleReloadWpCommand, rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA, Console::Yes }, + { "vehicle_accessory", HandleReloadVehicleAccessoryCommand, rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESSORY, Console::Yes }, + { "vehicle_template_accessory", HandleReloadVehicleTemplateAccessoryCommand, rbac::RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY, Console::Yes }, }; static ChatCommandTable commandTable = { @@ -579,6 +582,15 @@ public: return true; } + static bool HandleReloadRBACCommand(ChatHandler* handler) + { + LOG_INFO("rbac", "Reloading RBAC tables..."); + sAccountMgr->LoadRBAC(); + sWorld->ReloadRBAC(); + handler->SendGlobalGMSysMessage("RBAC data reloaded."); + return true; + } + static bool HandleReloadLootTemplatesCreatureCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Reloading Loot Tables... (`creature_loot_template`)"); diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index c3a6772cc..bc61aa5e0 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -21,6 +21,7 @@ #include "Language.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "ScriptMgr.h" #include "WorldSessionMgr.h" @@ -36,25 +37,25 @@ public: { static ChatCommandTable resetItemsCommandTable = { - { "equipped", HandleResetItemsEquippedCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "bags", HandleResetItemsInBagsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "bank", HandleResetItemsInBankCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "keyring", HandleResetItemsKeyringCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "currency", HandleResetItemsInCurrenciesListCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "vendor_buyback", HandleResetItemsInVendorBuyBackTabCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "all", HandleResetItemsAllCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "allbags", HandleResetItemsAllAndDeleteBagsCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "equipped", HandleResetItemsEquippedCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "bags", HandleResetItemsInBagsCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "bank", HandleResetItemsInBankCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "keyring", HandleResetItemsKeyringCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "currency", HandleResetItemsInCurrenciesListCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "vendor_buyback", HandleResetItemsInVendorBuyBackTabCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "all", HandleResetItemsAllCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, + { "allbags", HandleResetItemsAllAndDeleteBagsCommand, rbac::RBAC_PERM_COMMAND_RESET, Console::Yes }, }; static ChatCommandTable resetCommandTable = { - { "achievements", HandleResetAchievementsCommand, SEC_CONSOLE, Console::Yes }, - { "honor", HandleResetHonorCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "level", HandleResetLevelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spells", HandleResetSpellsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "stats", HandleResetStatsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "talents", HandleResetTalentsCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "items", resetItemsCommandTable }, - { "all", HandleResetAllCommand, SEC_CONSOLE, Console::Yes } + { "achievements", HandleResetAchievementsCommand, rbac::RBAC_PERM_COMMAND_RESET_ACHIEVEMENTS, Console::Yes }, + { "honor", HandleResetHonorCommand, rbac::RBAC_PERM_COMMAND_RESET_HONOR, Console::Yes }, + { "level", HandleResetLevelCommand, rbac::RBAC_PERM_COMMAND_RESET_LEVEL, Console::Yes }, + { "spells", HandleResetSpellsCommand, rbac::RBAC_PERM_COMMAND_RESET_SPELLS, Console::Yes }, + { "stats", HandleResetStatsCommand, rbac::RBAC_PERM_COMMAND_RESET_STATS, Console::Yes }, + { "talents", HandleResetTalentsCommand, rbac::RBAC_PERM_COMMAND_RESET_TALENTS, Console::Yes }, + { "items", resetItemsCommandTable }, + { "all", HandleResetAllCommand, rbac::RBAC_PERM_COMMAND_RESET_ALL, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp index 9507a4bdd..9ad077a6a 100644 --- a/src/server/scripts/Commands/cs_script_loader.cpp +++ b/src/server/scripts/Commands/cs_script_loader.cpp @@ -54,6 +54,7 @@ void AddSC_player_commandscript(); void AddSC_pool_commandscript(); void AddSC_pooltools_commandscript(); void AddSC_quest_commandscript(); +void AddSC_rbac_commandscript(); void AddSC_reload_commandscript(); void AddSC_reset_commandscript(); void AddSC_send_commandscript(); @@ -111,6 +112,7 @@ void AddCommandsScripts() AddSC_pool_commandscript(); AddSC_pooltools_commandscript(); AddSC_quest_commandscript(); + AddSC_rbac_commandscript(); AddSC_reload_commandscript(); AddSC_reset_commandscript(); AddSC_send_commandscript(); diff --git a/src/server/scripts/Commands/cs_send.cpp b/src/server/scripts/Commands/cs_send.cpp index ee74a22a0..3e3d6f56f 100644 --- a/src/server/scripts/Commands/cs_send.cpp +++ b/src/server/scripts/Commands/cs_send.cpp @@ -23,6 +23,7 @@ #include "ObjectMgr.h" #include "Pet.h" #include "Player.h" +#include "RBAC.h" #include "Tokenize.h" using namespace Acore::ChatCommands; @@ -36,10 +37,10 @@ public: { static ChatCommandTable sendCommandTable = { - { "items", HandleSendItemsCommand, SEC_GAMEMASTER, Console::Yes }, - { "mail", HandleSendMailCommand, SEC_GAMEMASTER, Console::Yes }, - { "message", HandleSendMessageCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "money", HandleSendMoneyCommand, SEC_GAMEMASTER, Console::Yes } + { "items", HandleSendItemsCommand, rbac::RBAC_PERM_COMMAND_SEND_ITEMS, Console::Yes }, + { "mail", HandleSendMailCommand, rbac::RBAC_PERM_COMMAND_SEND_MAIL, Console::Yes }, + { "message", HandleSendMessageCommand, rbac::RBAC_PERM_COMMAND_SEND_MESSAGE, Console::Yes }, + { "money", HandleSendMoneyCommand, rbac::RBAC_PERM_COMMAND_SEND_MONEY, Console::Yes } }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 63815aeec..3fc35ab18 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -25,6 +25,7 @@ #include "ModuleMgr.h" #include "MotdMgr.h" #include "MySQLThreading.h" +#include "RBAC.h" #include "Realm.h" #include "StringConvert.h" #include "UpdateTime.h" @@ -48,44 +49,44 @@ public: { static ChatCommandTable serverIdleRestartCommandTable = { - { "cancel", HandleServerShutDownCancelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "", HandleServerIdleRestartCommand, SEC_CONSOLE, Console::Yes } + { "cancel", HandleServerShutDownCancelCommand, rbac::RBAC_PERM_COMMAND_SERVER_IDLERESTART_CANCEL, Console::Yes }, + { "", HandleServerIdleRestartCommand, rbac::RBAC_PERM_COMMAND_SERVER_IDLERESTART, Console::Yes } }; static ChatCommandTable serverIdleShutdownCommandTable = { - { "cancel", HandleServerShutDownCancelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "", HandleServerIdleShutDownCommand, SEC_CONSOLE, Console::Yes } + { "cancel", HandleServerShutDownCancelCommand, rbac::RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN_CANCEL, Console::Yes }, + { "", HandleServerIdleShutDownCommand, rbac::RBAC_PERM_COMMAND_SERVER_IDLESHUTDOWN, Console::Yes } }; static ChatCommandTable serverRestartCommandTable = { - { "cancel", HandleServerShutDownCancelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "", HandleServerRestartCommand, SEC_ADMINISTRATOR, Console::Yes } + { "cancel", HandleServerShutDownCancelCommand, rbac::RBAC_PERM_COMMAND_SERVER_RESTART_CANCEL, Console::Yes }, + { "", HandleServerRestartCommand, rbac::RBAC_PERM_COMMAND_SERVER_RESTART, Console::Yes } }; static ChatCommandTable serverShutdownCommandTable = { - { "cancel", HandleServerShutDownCancelCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "", HandleServerShutDownCommand, SEC_ADMINISTRATOR, Console::Yes } + { "cancel", HandleServerShutDownCancelCommand, rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN_CANCEL, Console::Yes }, + { "", HandleServerShutDownCommand, rbac::RBAC_PERM_COMMAND_SERVER_SHUTDOWN, Console::Yes } }; static ChatCommandTable serverSetCommandTable = { - { "loglevel", HandleServerSetLogLevelCommand, SEC_CONSOLE, Console::Yes }, - { "motd", HandleServerSetMotdCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "closed", HandleServerSetClosedCommand, SEC_CONSOLE, Console::Yes }, + { "loglevel", HandleServerSetLogLevelCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_LOGLEVEL, Console::Yes }, + { "motd", HandleServerSetMotdCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_MOTD, Console::Yes }, + { "closed", HandleServerSetClosedCommand, rbac::RBAC_PERM_COMMAND_SERVER_SET_CLOSED, Console::Yes }, }; static ChatCommandTable serverCommandTable = { - { "corpses", HandleServerCorpsesCommand, SEC_GAMEMASTER, Console::Yes }, - { "debug", HandleServerDebugCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "exit", HandleServerExitCommand, SEC_CONSOLE, Console::Yes }, + { "corpses", HandleServerCorpsesCommand, rbac::RBAC_PERM_COMMAND_SERVER_CORPSES, Console::Yes }, + { "debug", HandleServerDebugCommand, rbac::RBAC_PERM_COMMAND_SERVER_DEBUG, Console::Yes }, + { "exit", HandleServerExitCommand, rbac::RBAC_PERM_COMMAND_SERVER_EXIT, Console::Yes }, { "idlerestart", serverIdleRestartCommandTable }, { "idleshutdown", serverIdleShutdownCommandTable }, - { "info", HandleServerInfoCommand, SEC_PLAYER, Console::Yes }, - { "motd", HandleServerMotdCommand, SEC_PLAYER, Console::Yes }, + { "info", HandleServerInfoCommand, rbac::RBAC_PERM_COMMAND_SERVER_INFO, Console::Yes }, + { "motd", HandleServerMotdCommand, rbac::RBAC_PERM_COMMAND_SERVER_MOTD, Console::Yes }, { "restart", serverRestartCommandTable }, { "shutdown", serverShutdownCommandTable }, { "set", serverSetCommandTable } diff --git a/src/server/scripts/Commands/cs_spectator.cpp b/src/server/scripts/Commands/cs_spectator.cpp index 86fbf6413..29ff8321c 100644 --- a/src/server/scripts/Commands/cs_spectator.cpp +++ b/src/server/scripts/Commands/cs_spectator.cpp @@ -20,6 +20,7 @@ #include "Chat.h" #include "CommandScript.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -32,12 +33,12 @@ public: { static ChatCommandTable spectatorCommandTable = { - { "version", HandleSpectatorVersionCommand, SEC_PLAYER, Console::No }, - { "reset", HandleSpectatorResetCommand, SEC_PLAYER, Console::No }, - { "spectate", HandleSpectatorSpectateCommand, SEC_PLAYER, Console::No }, - { "watch", HandleSpectatorWatchCommand, SEC_PLAYER, Console::No }, - { "leave", HandleSpectatorLeaveCommand, SEC_PLAYER, Console::No }, - { "", HandleSpectatorCommand, SEC_PLAYER, Console::No } + { "version", HandleSpectatorVersionCommand, rbac::RBAC_PERM_COMMAND_SPECT_VERSION, Console::No }, + { "reset", HandleSpectatorResetCommand, rbac::RBAC_PERM_COMMAND_SPECT_RESET, Console::No }, + { "spectate", HandleSpectatorSpectateCommand, rbac::RBAC_PERM_COMMAND_SPECT_SPECTATE, Console::No }, + { "watch", HandleSpectatorWatchCommand, rbac::RBAC_PERM_COMMAND_SPECT_WATCH, Console::No }, + { "leave", HandleSpectatorLeaveCommand, rbac::RBAC_PERM_COMMAND_SPECT_LEAVE, Console::No }, + { "", HandleSpectatorCommand, rbac::RBAC_PERM_COMMAND_SPECT, Console::No } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_tele.cpp b/src/server/scripts/Commands/cs_tele.cpp index aed43e503..ee8c9d796 100644 --- a/src/server/scripts/Commands/cs_tele.cpp +++ b/src/server/scripts/Commands/cs_tele.cpp @@ -23,6 +23,7 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -35,22 +36,22 @@ public: { static ChatCommandTable teleNameNpcCommandTable = { - { "id", HandleTeleNameNpcIdCommand, SEC_GAMEMASTER, Console::Yes }, - { "guid", HandleTeleNameNpcSpawnIdCommand, SEC_GAMEMASTER, Console::Yes }, - { "name", HandleTeleNameNpcNameCommand, SEC_GAMEMASTER, Console::Yes }, + { "id", HandleTeleNameNpcIdCommand, rbac::RBAC_PERM_COMMAND_TELE_NAME, Console::Yes }, + { "guid", HandleTeleNameNpcSpawnIdCommand, rbac::RBAC_PERM_COMMAND_TELE_NAME, Console::Yes }, + { "name", HandleTeleNameNpcNameCommand, rbac::RBAC_PERM_COMMAND_TELE_NAME, Console::Yes }, }; static ChatCommandTable teleNameCommandTable = { { "npc", teleNameNpcCommandTable }, - { "", HandleTeleNameCommand, SEC_GAMEMASTER, Console::Yes }, + { "", HandleTeleNameCommand, rbac::RBAC_PERM_COMMAND_TELE_NAME, Console::Yes }, }; static ChatCommandTable teleCommandTable = { - { "add", HandleTeleAddCommand, SEC_ADMINISTRATOR, Console::No }, - { "del", HandleTeleDelCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "add", HandleTeleAddCommand, rbac::RBAC_PERM_COMMAND_TELE_ADD, Console::No }, + { "del", HandleTeleDelCommand, rbac::RBAC_PERM_COMMAND_TELE_DEL, Console::Yes }, { "name", teleNameCommandTable }, - { "group", HandleTeleGroupCommand, SEC_GAMEMASTER, Console::No }, - { "", HandleTeleCommand, SEC_GAMEMASTER, Console::No } + { "group", HandleTeleGroupCommand, rbac::RBAC_PERM_COMMAND_TELE_GROUP, Console::No }, + { "", HandleTeleCommand, rbac::RBAC_PERM_COMMAND_TELE, Console::No } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index 0cd174b70..e54aad546 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -20,6 +20,7 @@ #include "CommandScript.h" #include "ObjectMgr.h" #include "Player.h" +#include "RBAC.h" #include "Realm.h" #include "TicketMgr.h" @@ -34,30 +35,30 @@ public: { static ChatCommandTable ticketResponseCommandTable = { - { "append", HandleGMTicketResponseAppendCommand, SEC_GAMEMASTER, Console::Yes }, - { "appendln", HandleGMTicketResponseAppendLnCommand, SEC_GAMEMASTER, Console::Yes }, - { "delete", HandleGMTicketResponseDeleteCommand, SEC_GAMEMASTER, Console::Yes }, - { "show", HandleGMTicketResponseShowCommand, SEC_GAMEMASTER, Console::Yes } + { "append", HandleGMTicketResponseAppendCommand, rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPEND, Console::Yes }, + { "appendln", HandleGMTicketResponseAppendLnCommand, rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPENDLN, Console::Yes }, + { "delete", HandleGMTicketResponseDeleteCommand, rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE, Console::Yes }, + { "show", HandleGMTicketResponseShowCommand, rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE, Console::Yes } }; static ChatCommandTable ticketCommandTable = { - { "assign", HandleGMTicketAssignToCommand, SEC_GAMEMASTER, Console::Yes }, - { "close", HandleGMTicketCloseByIdCommand, SEC_GAMEMASTER, Console::Yes }, - { "closedlist", HandleGMTicketListClosedCommand, SEC_GAMEMASTER, Console::Yes }, - { "comment", HandleGMTicketCommentCommand, SEC_GAMEMASTER, Console::Yes }, - { "complete", HandleGMTicketCompleteCommand, SEC_GAMEMASTER, Console::Yes }, - { "delete", HandleGMTicketDeleteByIdCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "escalate", HandleGMTicketEscalateCommand, SEC_GAMEMASTER, Console::Yes }, - { "escalatedlist", HandleGMTicketListEscalatedCommand, SEC_GAMEMASTER, Console::Yes }, - { "list", HandleGMTicketListCommand, SEC_GAMEMASTER, Console::Yes }, - { "onlinelist", HandleGMTicketListOnlineCommand, SEC_GAMEMASTER, Console::Yes }, - { "reset", HandleGMTicketResetCommand, SEC_CONSOLE, Console::Yes }, + { "assign", HandleGMTicketAssignToCommand, rbac::RBAC_PERM_COMMAND_TICKET_ASSIGN, Console::Yes }, + { "close", HandleGMTicketCloseByIdCommand, rbac::RBAC_PERM_COMMAND_TICKET_CLOSE, Console::Yes }, + { "closedlist", HandleGMTicketListClosedCommand, rbac::RBAC_PERM_COMMAND_TICKET_CLOSEDLIST, Console::Yes }, + { "comment", HandleGMTicketCommentCommand, rbac::RBAC_PERM_COMMAND_TICKET_COMMENT, Console::Yes }, + { "complete", HandleGMTicketCompleteCommand, rbac::RBAC_PERM_COMMAND_TICKET_COMPLETE, Console::Yes }, + { "delete", HandleGMTicketDeleteByIdCommand, rbac::RBAC_PERM_COMMAND_TICKET_DELETE, Console::Yes }, + { "escalate", HandleGMTicketEscalateCommand, rbac::RBAC_PERM_COMMAND_TICKET_ESCALATE, Console::Yes }, + { "escalatedlist", HandleGMTicketListEscalatedCommand, rbac::RBAC_PERM_COMMAND_TICKET_ESCALATEDLIST, Console::Yes }, + { "list", HandleGMTicketListCommand, rbac::RBAC_PERM_COMMAND_TICKET_LIST, Console::Yes }, + { "onlinelist", HandleGMTicketListOnlineCommand, rbac::RBAC_PERM_COMMAND_TICKET_ONLINELIST, Console::Yes }, + { "reset", HandleGMTicketResetCommand, rbac::RBAC_PERM_COMMAND_TICKET_RESET, Console::Yes }, { "response", ticketResponseCommandTable }, - { "togglesystem", HandleToggleGMTicketSystem, SEC_ADMINISTRATOR, Console::Yes }, - { "unassign", HandleGMTicketUnAssignCommand, SEC_GAMEMASTER, Console::Yes }, - { "viewid", HandleGMTicketGetByIdCommand, SEC_GAMEMASTER, Console::Yes }, - { "viewname", HandleGMTicketGetByNameCommand, SEC_GAMEMASTER, Console::Yes } + { "togglesystem", HandleToggleGMTicketSystem, rbac::RBAC_PERM_COMMAND_TICKET_TOGGLESYSTEM, Console::Yes }, + { "unassign", HandleGMTicketUnAssignCommand, rbac::RBAC_PERM_COMMAND_TICKET_UNASSIGN, Console::Yes }, + { "viewid", HandleGMTicketGetByIdCommand, rbac::RBAC_PERM_COMMAND_TICKET_VIEWID, Console::Yes }, + { "viewname", HandleGMTicketGetByNameCommand, rbac::RBAC_PERM_COMMAND_TICKET_VIEWNAME, Console::Yes } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/Commands/cs_titles.cpp b/src/server/scripts/Commands/cs_titles.cpp index 51c254724..38a35f5f7 100644 --- a/src/server/scripts/Commands/cs_titles.cpp +++ b/src/server/scripts/Commands/cs_titles.cpp @@ -19,6 +19,7 @@ #include "CommandScript.h" #include "DBCStores.h" #include "Player.h" +#include "RBAC.h" using namespace Acore::ChatCommands; @@ -31,13 +32,13 @@ public: { static ChatCommandTable titlesSetCommandTable = { - { "mask", HandleTitlesSetMaskCommand, SEC_GAMEMASTER, Console::No }, + { "mask", HandleTitlesSetMaskCommand, rbac::RBAC_PERM_COMMAND_TITLES_SET_MASK, Console::No }, }; static ChatCommandTable titlesCommandTable = { - { "add", HandleTitlesAddCommand, SEC_GAMEMASTER, Console::No }, - { "current", HandleTitlesCurrentCommand, SEC_GAMEMASTER, Console::No }, - { "remove", HandleTitlesRemoveCommand, SEC_GAMEMASTER, Console::No }, + { "add", HandleTitlesAddCommand, rbac::RBAC_PERM_COMMAND_TITLES_ADD, Console::No }, + { "current", HandleTitlesCurrentCommand, rbac::RBAC_PERM_COMMAND_TITLES_CURRENT, Console::No }, + { "remove", HandleTitlesRemoveCommand, rbac::RBAC_PERM_COMMAND_TITLES_REMOVE, Console::No }, { "set", titlesSetCommandTable }, }; static ChatCommandTable commandTable = diff --git a/src/server/scripts/Commands/cs_worldstate.cpp b/src/server/scripts/Commands/cs_worldstate.cpp index e6d9c833d..535aadbaf 100644 --- a/src/server/scripts/Commands/cs_worldstate.cpp +++ b/src/server/scripts/Commands/cs_worldstate.cpp @@ -18,6 +18,7 @@ #include "Chat.h" #include "CommandScript.h" #include "Common.h" +#include "RBAC.h" #include "WorldState.h" using namespace Acore::ChatCommands; @@ -31,20 +32,20 @@ public: { static ChatCommandTable sunsreachCommandTable = { - { "status", HandleSunsReachReclamationStatusCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "phase", HandleSunsReachReclamationPhaseCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "subphase", HandleSunsReachReclamationSubPhaseCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "counter", HandleSunsReachReclamationCounterCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gate", HandleSunwellGateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "gatecounter", HandleSunwellGateCounterCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "status", HandleSunsReachReclamationStatusCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "phase", HandleSunsReachReclamationPhaseCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "subphase", HandleSunsReachReclamationSubPhaseCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "counter", HandleSunsReachReclamationCounterCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "gate", HandleSunwellGateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "gatecounter", HandleSunwellGateCounterCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, }; static ChatCommandTable scourgeInvasionCommandTable = { - { "show", HandleScourgeInvasionCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "state", HandleScourgeInvasionStateCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "battleswon", HandleScourgeInvasionBattlesWonCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "startzone", HandleScourgeInvasionStartZone, SEC_ADMINISTRATOR, Console::Yes }, + { "show", HandleScourgeInvasionCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "state", HandleScourgeInvasionStateCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "battleswon", HandleScourgeInvasionBattlesWonCommand, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, + { "startzone", HandleScourgeInvasionStartZone, rbac::RBAC_PERM_COMMAND_DEBUG, Console::Yes }, }; static ChatCommandTable worldStateCommandTable = diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index b4b80686a..efd07cf48 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -18,6 +18,7 @@ #include "Chat.h" #include "CommandScript.h" #include "Player.h" +#include "RBAC.h" #include "WaypointMgr.h" #if AC_COMPILER == AC_COMPILER_GNU @@ -35,13 +36,13 @@ public: { static ChatCommandTable wpCommandTable = { - { "add", HandleWpAddCommand, SEC_ADMINISTRATOR, Console::No }, - { "event", HandleWpEventCommand, SEC_ADMINISTRATOR, Console::No }, - { "load", HandleWpLoadCommand, SEC_ADMINISTRATOR, Console::No }, - { "modify", HandleWpModifyCommand, SEC_ADMINISTRATOR, Console::No }, - { "unload", HandleWpUnLoadCommand, SEC_ADMINISTRATOR, Console::No }, - { "reload", HandleWpReloadCommand, SEC_ADMINISTRATOR, Console::No }, - { "show", HandleWpShowCommand, SEC_ADMINISTRATOR, Console::No } + { "add", HandleWpAddCommand, rbac::RBAC_PERM_COMMAND_WP_ADD, Console::No }, + { "event", HandleWpEventCommand, rbac::RBAC_PERM_COMMAND_WP_EVENT, Console::No }, + { "load", HandleWpLoadCommand, rbac::RBAC_PERM_COMMAND_WP_LOAD, Console::No }, + { "modify", HandleWpModifyCommand, rbac::RBAC_PERM_COMMAND_WP_MODIFY, Console::No }, + { "unload", HandleWpUnLoadCommand, rbac::RBAC_PERM_COMMAND_WP_UNLOAD, Console::No }, + { "reload", HandleWpReloadCommand, rbac::RBAC_PERM_COMMAND_WP_RELOAD, Console::No }, + { "show", HandleWpShowCommand, rbac::RBAC_PERM_COMMAND_WP_SHOW, Console::No } }; static ChatCommandTable commandTable = { diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp index a77af22d0..62932fe2e 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -181,21 +181,6 @@ struct instance_blackwing_lair : public InstanceScript return 0; } - bool CheckRequiredBosses(uint32 bossId, Player const* /* player */) const override - { - switch (bossId) - { - case DATA_BROODLORD_LASHLAYER: - if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE) - return false; - break; - default: - break; - } - - return true; - } - bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) @@ -304,6 +289,24 @@ struct instance_blackwing_lair : public InstanceScript return ObjectGuid::Empty; } + bool CheckRequiredBosses(uint32 bossId, Player const* player) const override + { + if (_SkipCheckRequiredBosses(player)) + return true; + + switch (bossId) + { + case DATA_BROODLORD_LASHLAYER: + if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE) + return false; + break; + default: + break; + } + + return true; + } + void OnUnitDeath(Unit* unit) override { switch (unit->GetEntry()) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index 654ee2289..bc93a0303 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -82,11 +82,6 @@ struct boss_attumen : public BossAI Initialize(); } - bool CanMeleeHit() - { - return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); - } - void EnterEvadeMode(EvadeReason why) override { if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) @@ -215,18 +210,10 @@ struct boss_attumen : public BossAI void UpdateAI(uint32 diff) override { - if (_phase != PHASE_NONE) - { - if (!UpdateVictim()) - { - return; - } - } - if (!CanMeleeHit()) - { - BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); - } - scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this)); + if (_phase != PHASE_NONE && !UpdateVictim()) + return; + + scheduler.Update(diff, [this] { DoMeleeAttackIfReady(); }); } void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index c683a4961..a771c067f 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "AreaBoundary.h" #include "Creature.h" #include "GameObject.h" #include "InstanceMapScript.h" @@ -65,6 +66,12 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } }; +BossBoundaryData const boundaries = +{ + { DATA_ATTUMEN, new CircleBoundary(Position(-11126.3f, -1929.11f), 50.0f) }, + { DATA_ATTUMEN, new ZRangeBoundary(49.0f, 55.0f) }, +}; + class instance_karazhan : public InstanceMapScript { public: @@ -81,6 +88,7 @@ public: { SetHeaders(DataHeader); SetBossNumber(EncounterCount); + LoadBossBoundaries(boundaries); LoadObjectData(creatureData, gameObjectData); LoadDoorData(doorData); diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index 9ed4f962d..fb1670616 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -924,6 +924,7 @@ struct boss_sartharion_dragonAI : public BossAI // Dragon speaks and starts flying to landing position Talk(SAY_DRAKE_RESPOND); me->GetMotionMaster()->Clear(); + extraEvents.CancelEvent(EVENT_DRAGON_PATROL_WAYPOINT); me->SetDisableGravity(true); me->SetHover(true); me->SetAnimTier(AnimTier::Fly); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 3f0b45490..6b2077677 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -1421,10 +1421,8 @@ public: bool CheckRequiredBosses(uint32 bossId, Player const* player) const override { - if (player && player->GetSession() && player->GetSession()->GetSecurity() >= SEC_MODERATOR) - { + if (_SkipCheckRequiredBosses(player)) return true; - } switch (bossId) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index abb53e6e2..7f28e2301 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -680,10 +680,34 @@ class spell_kelthuzad_detonate_mana_aura : public AuraScript } }; +class spell_kelthuzad_void_blast : public SpellScript +{ + PrepareSpellScript(spell_kelthuzad_void_blast); + + void HandleAfterHit() + { + Player* player = GetHitPlayer(); + if (!player) + return; + + if (player->IsAlive()) + return; + + if (InstanceScript* instance = player->GetInstanceScript()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); + } + + void Register() override + { + AfterHit += SpellHitFn(spell_kelthuzad_void_blast::HandleAfterHit); + } +}; + void AddSC_boss_kelthuzad() { new boss_kelthuzad(); new boss_kelthuzad_minion(); RegisterSpellScript(spell_kelthuzad_frost_blast); RegisterSpellScript(spell_kelthuzad_detonate_mana_aura); + RegisterSpellScript(spell_kelthuzad_void_blast); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index 25d46fcbd..78be3def6 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -113,49 +113,37 @@ public: { case EVENT_HATEFUL_STRIKE: { - // Cast Hateful strike on the player with the highest amount of HP within melee distance, and second threat amount - std::list meleeRangeTargets; - Unit* finalTarget = nullptr; - uint8 counter = 0; - auto threatList = me->GetThreatMgr().GetSortedThreatList(); - for (auto i = threatList.begin(); i != threatList.end(); ++i, ++counter) + // Scan melee targets (melee range), choose target according to mechanics: + // - If only 1 melee target exists, hit the tank (current victim). + // - Otherwise select the top RAID_MODE(1,2) threat targets (excluding current victim) + // among melee targets and hit the one with the highest HP. + // - The target hit gains 500 flat threat. + + Unit* victim = me->GetVictim(); + if (!victim) { - // Gather all units with melee range - Unit* target = (*i)->GetVictim(); - if (me->IsWithinMeleeRange(target)) - { - meleeRangeTargets.push_back(target); - } - // and add threat to most hated - if (counter < RAID_MODE(2, 3)) - { - me->AddThreat(target, 500.0f); - } + events.RescheduleEvent(EVENT_HATEFUL_STRIKE, 1s); + break; } - counter = 0; - std::list>::iterator itr; - for (itr = meleeRangeTargets.begin(); itr != meleeRangeTargets.end(); ++itr, ++counter) + + Unit* hatefulTarget = victim; // default to current victim if no other target is available + + std::list meleeTargets; + constexpr float HATEFUL_STRIKE_RANGE = 5.0f; + SelectTargetList(meleeTargets, RAID_MODE(1, 2), SelectTargetMethod::MaxThreat, 0, [&](Unit const* target) { - // if there is only one target available - if (meleeRangeTargets.size() == 1) - { - finalTarget = (*itr); - } - else if (counter > 0) // skip first target - { - if (!finalTarget || (*itr)->GetHealth() > finalTarget->GetHealth()) - { - finalTarget = (*itr); - } - // third loop - if (counter >= 2) - break; - } - } - if (finalTarget) + return target && target->IsPlayer() && target != victim && me->IsWithinCombatRange(target, HATEFUL_STRIKE_RANGE); + }); + + if (!meleeTargets.empty()) { - me->CastSpell(finalTarget, SPELL_HATEFUL_STRIKE, false); + meleeTargets.sort(Acore::HealthOrderPred(false)); + hatefulTarget = meleeTargets.front(); } + + me->CastSpell(hatefulTarget, SPELL_HATEFUL_STRIKE, false); + me->AddThreat(hatefulTarget, 500.0f); + events.Repeat(1s); break; } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index cb3668d45..3be8247d1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -48,6 +48,11 @@ enum FreyaSpells SPELL_UNSTABLE_SUN_FREYA_DAMAGE = 62451, SPELL_UNSTABLE_SUN_VISUAL = 62216, + // CHANNEL STALKER VISUALS + SPELL_FREYA_DUMMY_GREEN = 63295, + SPELL_FREYA_DUMMY_YELLOW = 63292, + SPELL_FREYA_DUMMY_BLUE = 63294, + // ELDERS SPELL_DRAINED_OF_POWER = 62467, SPELL_STONEBARK_ESSENCE = 62483, @@ -164,6 +169,7 @@ enum Texts enum FreyaNPCs { NPC_NATURE_BOMB = 34129, + NPC_CHANNEL_STALKER_FREYA = 33575, NPC_IRON_ROOT_TRIGGER = 33088, NPC_FREYA_UNSTABLE_SUN_BEAM = 33170, NPC_UNSTABLE_SUN_BRIGHTLEAF = 33050, // 10 SECS? @@ -196,6 +202,10 @@ enum Misc DATA_BACK_TO_NATURE = 2, CRITERIA_LUMBERJACKED = 21686, + + WAYPOINT_GREEN = 4, // path: 1365540 + WAYPOINT_YELLOW = 10, + WAYPOINT_BLUE = 18, }; struct boss_freya : public BossAI @@ -591,6 +601,31 @@ struct boss_freya : public BossAI { return me->GetPositionX() < 2135.0f; } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != WAYPOINT_MOTION_TYPE) + return; + + Unit* target = GetClosestCreatureWithEntry(me, NPC_CHANNEL_STALKER_FREYA, 30.0f); + if (!target) + return; + + switch (pointId) + { + case WAYPOINT_GREEN: + DoCast(target, SPELL_FREYA_DUMMY_GREEN); + break; + case WAYPOINT_YELLOW: + DoCast(target, SPELL_FREYA_DUMMY_YELLOW); + break; + case WAYPOINT_BLUE: + DoCast(target, SPELL_FREYA_DUMMY_BLUE); + break; + default: + break; + } + } }; struct boss_freya_elder_stonebark : public ScriptedAI diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index ce6a3a79b..c3fa1bac4 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -23,6 +23,7 @@ #include "ScriptedEscortAI.h" #include "ScriptedFollowerAI.h" #include "ScriptedGossip.h" +#include "SmartAI.h" #include "SpellAuras.h" #include "SpellInfo.h" #include "SpellScript.h" @@ -55,6 +56,8 @@ class spell_q11919_q11940_drake_hunt_aura : public AuraScript Creature* owner = GetOwner()->ToCreature(); owner->RemoveAllAurasExceptType(SPELL_AURA_DUMMY); + if (SmartAI* ai = CAST_AI(SmartAI, owner->AI())) + ai->SetEvadeDisabled(true); owner->CombatStop(true); owner->GetThreatMgr().ClearAllThreat(); owner->GetMotionMaster()->Clear(false); diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 853043860..5140656c0 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -538,39 +538,46 @@ public: } }; -enum HyldsmeetProtoDrake -{ - NPC_HYLDSMEET_DRAKERIDER = 29694 -}; - struct npc_hyldsmeet_protodrake : public CreatureAI { - explicit npc_hyldsmeet_protodrake(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0) { } + explicit npc_hyldsmeet_protodrake(Creature* creature) : CreatureAI(creature), _accessoryInstalled(false), _accessoryRespawnTimer(0) + { + me->SetUnitFlag2(UNIT_FLAG2_PREVENT_SPELL_CLICK); + } void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override { - if (apply) + if (who->IsPlayer()) return; - if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER) + if (apply) + _accessoryInstalled = true; + else + { + _accessoryInstalled = false; _accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS; + } } void UpdateAI(uint32 diff) override { - //! We need to manually reinstall accessories because the vehicle itself is friendly to players, - //! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable. + // We need to manually reinstall accessories because the vehicle itself is friendly to players, + // so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable. + if (_accessoryInstalled) + return; + Vehicle* vehicleKit = me->GetVehicleKit(); - if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && vehicleKit) - { + if (!vehicleKit) + return; + + if (_accessoryRespawnTimer <= diff) vehicleKit->InstallAllAccessories(true); - _accessoryRespawnTimer = 0; - } else _accessoryRespawnTimer -= diff; } private: + bool _accessoryInstalled; uint32 _accessoryRespawnTimer; }; diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index b8dfd4deb..97c9fdf91 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -469,38 +469,51 @@ public: struct go_beaconAI : public GameObjectAI { - go_beaconAI(GameObject* gameObject) : GameObjectAI(gameObject) { } + explicit go_beaconAI(GameObject* gameObject) : GameObjectAI(gameObject) { } - std::list creatureList; - - void OnStateChanged(uint32 state, Unit* /*unit*/) override + void OnStateChanged(uint32 state, Unit* /*unit*/) override { if (state == GO_ACTIVATED) { + std::list creatureList; + + _whelpGUIDs.clear(); me->GetCreaturesWithEntryInRange(creatureList, 40, NPC_STONESCHYE_WHELP); + + for (Creature* whelp : creatureList) { - for (Creature* whelp : creatureList) - { - if (whelp && whelp->IsAlive() && !whelp->IsInCombat() && whelp->GetMotionMaster()->GetCurrentMovementGeneratorType() != HOME_MOTION_TYPE) - whelp->GetMotionMaster()->MovePoint(0, me->GetNearPosition(4.0f, whelp->GetOrientation())); - } + if (!whelp) + continue; + + _whelpGUIDs.push_back(whelp->GetGUID()); + + MotionMaster* motionMaster = whelp->GetMotionMaster(); + if (whelp->IsAlive() && !whelp->IsInCombat() && motionMaster && motionMaster->GetCurrentMovementGeneratorType() != HOME_MOTION_TYPE) + motionMaster->MovePoint(0, me->GetNearPosition(4.0f, whelp->GetOrientation())); } } else if (state == GO_JUST_DEACTIVATED) { + for (ObjectGuid const& guid : _whelpGUIDs) { - for (Creature* whelp : creatureList) + if (Creature* whelp = ObjectAccessor::GetCreature(*me, guid)) { - if (whelp && whelp->IsAlive() && !whelp->IsInCombat() && whelp->GetMotionMaster()->GetCurrentMovementGeneratorType() != HOME_MOTION_TYPE) - whelp->GetMotionMaster()->MoveTargetedHome(); + MotionMaster* motionMaster = whelp->GetMotionMaster(); + if (whelp->IsAlive() && !whelp->IsInCombat() && motionMaster && motionMaster->GetCurrentMovementGeneratorType() != HOME_MOTION_TYPE) + motionMaster->MoveTargetedHome(); } } + + _whelpGUIDs.clear(); } else { - creatureList.clear(); + _whelpGUIDs.clear(); } } + + private: + GuidList _whelpGUIDs; }; GameObjectAI* GetAI(GameObject* go) const override diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp index 0d032ce14..5988b4bdd 100644 --- a/src/server/scripts/Outland/zone_terokkar_forest.cpp +++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp @@ -231,7 +231,9 @@ enum UnkorTheRuthless FACTION_HOSTILE = 45, QUEST_DONTKILLTHEFATONE = 9889, - SPELL_PULVERIZE = 2676 + SPELL_PULVERIZE = 2676, + + SUBMIT_DURATION = 120000 }; class npc_unkor_the_ruthless : public CreatureScript @@ -248,22 +250,28 @@ public: { npc_unkor_the_ruthlessAI(Creature* creature) : ScriptedAI(creature) { } - bool CanDoQuest; - uint32 UnkorUnfriendly_Timer; - uint32 Pulverize_Timer; + bool Submitted; + uint32 UnfriendlyTimer; + uint32 PulverizeTimer; void Reset() override { - CanDoQuest = false; - UnkorUnfriendly_Timer = 0; - Pulverize_Timer = 3000; + Submitted = false; + UnfriendlyTimer = 0; + PulverizeTimer = 3000; me->SetStandState(UNIT_STAND_STATE_STAND); me->SetFaction(FACTION_HOSTILE); } void JustEngagedWith(Unit* /*who*/) override { } - void DoNice() + bool HasQuestActive(Player* player) const + { + QuestStatus status = player->GetQuestStatus(QUEST_DONTKILLTHEFATONE); + return status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE; + } + + void Submit() { Talk(SAY_SUBMIT); me->SetFaction(FACTION_FRIENDLY); @@ -271,7 +279,8 @@ public: me->RemoveAllAuras(); me->GetThreatMgr().ClearAllThreat(); me->CombatStop(true); - UnkorUnfriendly_Timer = 60000; + Submitted = true; + UnfriendlyTimer = SUBMIT_DURATION; } void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType, SpellSchoolMask) override @@ -280,61 +289,47 @@ public: return; Player* player = done_by->ToPlayer(); - if (player && me->HealthBelowPctDamaged(30, damage)) - { - if (Group* group = player->GetGroup()) - { - for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - { - Player* groupie = itr->GetSource(); - if (groupie && groupie->IsInMap(player) && - groupie->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) - { - groupie->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); - if (!CanDoQuest) - CanDoQuest = true; - } - } - } - else if (player->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - player->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) - { - player->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); - CanDoQuest = true; - } - } + if (!player) + if (Unit* owner = done_by->GetOwner()) + player = owner->ToPlayer(); + if (!player || !HasQuestActive(player)) + return; + + // Cap damage from quest holders so DoTs/pets/burst can't kill him. + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!me->HealthBelowPctDamaged(30, damage)) + return; + + player->GroupEventHappens(QUEST_DONTKILLTHEFATONE, me); + + if (!Submitted) + Submit(); } void UpdateAI(uint32 diff) override { - if (CanDoQuest) + if (Submitted) { - if (!UnkorUnfriendly_Timer) + if (UnfriendlyTimer <= diff) { - //DoCast(me, SPELL_QUID9889); //not using spell for now - DoNice(); - } - else - { - if (UnkorUnfriendly_Timer <= diff) - { - EnterEvadeMode(); - return; - } - else UnkorUnfriendly_Timer -= diff; + EnterEvadeMode(); + return; } + UnfriendlyTimer -= diff; + return; } if (!UpdateVictim()) return; - if (Pulverize_Timer <= diff) + if (PulverizeTimer <= diff) { DoCast(me, SPELL_PULVERIZE); - Pulverize_Timer = 9000; + PulverizeTimer = 9000; } - else Pulverize_Timer -= diff; + else PulverizeTimer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index bbf9bb52e..65596dd4a 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -381,27 +381,20 @@ class spell_q12943_shadow_vault_decree : public SpellScript { PrepareSpellScript(spell_q12943_shadow_vault_decree); - SpellCastResult CheckRequirement() - { - // if thane is present and not in combat - allow cast - Unit* caster = GetCaster(); - if (Creature* thane = caster->FindNearestCreature(NPC_THANE_UFRANG, 30.0f)) - if (!thane->IsInCombat()) - return SPELL_CAST_OK; - - return SPELL_FAILED_CASTER_AURASTATE; - } - void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Creature* thane = caster->FindNearestCreature(NPC_THANE_UFRANG, 30.0f)) + { + if (thane->IsInCombat()) + return; + thane->ReplaceAllUnitFlags(UNIT_FLAG_NONE); thane->AI()->AttackStart(caster); + } } void Register() override { - OnCheckCast += SpellCheckCastFn(spell_q12943_shadow_vault_decree::CheckRequirement); OnEffectHitTarget += SpellEffectFn(spell_q12943_shadow_vault_decree::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 902193daf..75970cc8e 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1559,7 +1559,8 @@ public: enum AmberpineOuthouse { QUEST_DOING_YOUR_DUTY = 12227, - SPELL_INDISPOSED = 53017, + SPELL_INDISPOSED_MALE = 48323, + SPELL_INDISPOSED_FEMALE = 53017, SPELL_INDISPOSED_II = 48324, SPELL_INDISPOSED_III = 48341, GOSSIP_OUTHOUSE_INUSE = 12775, @@ -1592,7 +1593,17 @@ public: if (action == GOSSIP_ACTION_INFO_DEF + 1) { CloseGossipMenuFor(player); - player->CastSpell(player, SPELL_INDISPOSED); + switch (player->getGender()) + { + case GENDER_FEMALE: + player->CastSpell(player, SPELL_INDISPOSED_FEMALE); + break; + case GENDER_MALE: + player->CastSpell(player, SPELL_INDISPOSED_MALE); + break; + default: + break; + } player->CastSpell(player, SPELL_INDISPOSED_II); player->CastSpell(player, SPELL_INDISPOSED_III); return true; diff --git a/src/test/mocks/WorldMock.h b/src/test/mocks/WorldMock.h index b37044119..e96e38b47 100644 --- a/src/test/mocks/WorldMock.h +++ b/src/test/mocks/WorldMock.h @@ -85,6 +85,7 @@ public: MOCK_METHOD(std::string const&, GetRealmName, (), (const)); MOCK_METHOD(void, SetRealmName, (std::string name), ()); MOCK_METHOD(void, RemoveOldCorpses, ()); + MOCK_METHOD(void, ReloadRBAC, ()); }; #pragma GCC diagnostic pop diff --git a/src/test/server/game/Accounts/RBACTest.cpp b/src/test/server/game/Accounts/RBACTest.cpp new file mode 100644 index 000000000..d48bd274e --- /dev/null +++ b/src/test/server/game/Accounts/RBACTest.cpp @@ -0,0 +1,2059 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/** + * @file RBACTest.cpp + * @brief Unit tests for the Role-Based Access Control (RBAC) system. + * + * Tests verify: + * 1. RBACPermission class construction and accessors + * 2. RBACData grant/deny/revoke operations + * 3. Permission state transitions + * 4. HasPermission checks with granted/denied lists + */ + +#include "AccountMgr.h" +#include "RBAC.h" +#include "gtest/gtest.h" +#include + +namespace +{ + +// Test permission IDs +constexpr uint32 TEST_PERM_1 = 1; +constexpr uint32 TEST_PERM_2 = 2; +constexpr uint32 TEST_PERM_3 = 3; +constexpr uint32 TEST_PERM_ROLE = 100; +constexpr uint32 TEST_PERM_INVALID = 99999; + +// Test account/realm data +constexpr uint32 TEST_ACCOUNT_ID = 1; +constexpr uint32 TEST_REALM_ID = 1; +constexpr uint8 TEST_SEC_LEVEL = 3; +const std::string TEST_ACCOUNT_NAME = "TestAccount"; + +/** + * @class RBACPermissionTest + * @brief Tests for RBACPermission class functionality. + */ +class RBACPermissionTest : public ::testing::Test +{ +protected: + void SetUp() override + { + permission = std::make_unique(TEST_PERM_1, "Test Permission"); + } + + std::unique_ptr permission; +}; + +// cppcheck-suppress syntaxError +TEST_F(RBACPermissionTest, Constructor_SetsIdAndName) +{ + EXPECT_EQ(permission->GetId(), TEST_PERM_1); + EXPECT_EQ(permission->GetName(), "Test Permission"); +} + +TEST_F(RBACPermissionTest, LinkedPermissions_InitiallyEmpty) +{ + EXPECT_TRUE(permission->GetLinkedPermissions().empty()); +} + +TEST_F(RBACPermissionTest, AddLinkedPermission_AddsToSet) +{ + permission->AddLinkedPermission(TEST_PERM_2); + permission->AddLinkedPermission(TEST_PERM_3); + + auto const& linked = permission->GetLinkedPermissions(); + EXPECT_EQ(linked.size(), 2u); + EXPECT_TRUE(linked.count(TEST_PERM_2) > 0); + EXPECT_TRUE(linked.count(TEST_PERM_3) > 0); +} + +TEST_F(RBACPermissionTest, AddLinkedPermission_NoDuplicates) +{ + permission->AddLinkedPermission(TEST_PERM_2); + permission->AddLinkedPermission(TEST_PERM_2); + permission->AddLinkedPermission(TEST_PERM_2); + + EXPECT_EQ(permission->GetLinkedPermissions().size(), 1u); +} + +/** + * @class RBACDataTest + * @brief Tests for RBACData class functionality with full server setup. + * + * Uses AccountMgr's test permission registration to allow proper + * GrantPermission/DenyPermission testing. + */ +class RBACDataTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Register test permissions with AccountMgr + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Test Permission 1"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Test Permission 2"); + sAccountMgr->AddPermissionForTest(TEST_PERM_3, "Test Permission 3"); + sAccountMgr->AddPermissionForTest(TEST_PERM_ROLE, "Test Role Permission"); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + // Clean up test permissions + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACDataTest, Constructor_SetsAccountData) +{ + EXPECT_EQ(rbacData->GetId(), TEST_ACCOUNT_ID); + EXPECT_EQ(rbacData->GetName(), TEST_ACCOUNT_NAME); + EXPECT_EQ(rbacData->GetSecurityLevel(), TEST_SEC_LEVEL); +} + +TEST_F(RBACDataTest, InitialState_EmptyPermissions) +{ + EXPECT_TRUE(rbacData->GetGrantedPermissions().empty()); + EXPECT_TRUE(rbacData->GetDeniedPermissions().empty()); +} + +// Grant Permission Tests + +TEST_F(RBACDataTest, GrantPermission_Success) +{ + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + EXPECT_TRUE(rbacData->GetGrantedPermissions().count(TEST_PERM_1) > 0); +} + +TEST_F(RBACDataTest, GrantPermission_AlreadyGranted_ReturnsError) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_CANT_ADD_ALREADY_ADDED); +} + +TEST_F(RBACDataTest, GrantPermission_WhenDenied_ReturnsError) +{ + rbacData->DenyPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_IN_DENIED_LIST); +} + +TEST_F(RBACDataTest, GrantPermission_InvalidId_ReturnsError) +{ + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_INVALID); + EXPECT_EQ(result, rbac::RBAC_ID_DOES_NOT_EXISTS); +} + +// Deny Permission Tests + +TEST_F(RBACDataTest, DenyPermission_Success) +{ + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + EXPECT_TRUE(rbacData->GetDeniedPermissions().count(TEST_PERM_1) > 0); +} + +TEST_F(RBACDataTest, DenyPermission_AlreadyDenied_ReturnsError) +{ + rbacData->DenyPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_CANT_ADD_ALREADY_ADDED); +} + +TEST_F(RBACDataTest, DenyPermission_WhenGranted_ReturnsError) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_IN_GRANTED_LIST); +} + +TEST_F(RBACDataTest, DenyPermission_InvalidId_ReturnsError) +{ + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_INVALID); + EXPECT_EQ(result, rbac::RBAC_ID_DOES_NOT_EXISTS); +} + +// Revoke Permission Tests + +TEST_F(RBACDataTest, RevokePermission_FromGranted_Success) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + EXPECT_TRUE(rbacData->GetGrantedPermissions().empty()); +} + +TEST_F(RBACDataTest, RevokePermission_FromDenied_Success) +{ + rbacData->DenyPermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + EXPECT_TRUE(rbacData->GetDeniedPermissions().empty()); +} + +TEST_F(RBACDataTest, RevokePermission_NotInList_ReturnsError) +{ + rbac::RBACCommandResult result = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); +} + +// HasPermission Tests + +TEST_F(RBACDataTest, HasPermission_WhenGranted_ReturnsTrue) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACDataTest, HasPermission_WhenDenied_ReturnsFalse) +{ + rbacData->DenyPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACDataTest, HasPermission_WhenNotSet_ReturnsFalse) +{ + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); +} + +// Multiple Permissions Tests + +TEST_F(RBACDataTest, MultiplePermissions_IndependentTracking) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->DenyPermission(TEST_PERM_2); + rbacData->GrantPermission(TEST_PERM_3); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_2)); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_3)); + + EXPECT_EQ(rbacData->GetGrantedPermissions().size(), 2u); + EXPECT_EQ(rbacData->GetDeniedPermissions().size(), 1u); +} + +TEST_F(RBACDataTest, RevokeAndRegrant_WorksCorrectly) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + + rbacData->RevokePermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + + // Now can grant again + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACDataTest, RevokeAndDeny_WorksCorrectly) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + + rbacData->RevokePermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + + // Now can deny + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + EXPECT_TRUE(rbacData->GetDeniedPermissions().count(TEST_PERM_1) > 0); +} + +/** + * @class RBACCommandResultTest + * @brief Tests to verify all RBACCommandResult values are handled. + */ +class RBACCommandResultTest : public ::testing::Test +{ +}; + +TEST_F(RBACCommandResultTest, AllResultValuesAreDefined) +{ + // Verify enum values exist and are distinct + EXPECT_NE(rbac::RBAC_OK, rbac::RBAC_CANT_ADD_ALREADY_ADDED); + EXPECT_NE(rbac::RBAC_OK, rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); + EXPECT_NE(rbac::RBAC_OK, rbac::RBAC_IN_GRANTED_LIST); + EXPECT_NE(rbac::RBAC_OK, rbac::RBAC_IN_DENIED_LIST); + EXPECT_NE(rbac::RBAC_OK, rbac::RBAC_ID_DOES_NOT_EXISTS); +} + +/** + * @class RBACLinkedPermissionsTest + * @brief Tests for permission inheritance through linked permissions. + */ +class RBACLinkedPermissionsTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Register test permissions + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Base Permission 1"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Base Permission 2"); + sAccountMgr->AddPermissionForTest(TEST_PERM_3, "Base Permission 3"); + sAccountMgr->AddPermissionForTest(TEST_PERM_ROLE, "Role Permission"); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACLinkedPermissionsTest, GrantedPermission_IsInGrantedList) +{ + rbacData->GrantPermission(TEST_PERM_1); + + auto const& granted = rbacData->GetGrantedPermissions(); + EXPECT_TRUE(granted.count(TEST_PERM_1) > 0); +} + +TEST_F(RBACLinkedPermissionsTest, DeniedPermission_IsInDeniedList) +{ + rbacData->DenyPermission(TEST_PERM_1); + + auto const& denied = rbacData->GetDeniedPermissions(); + EXPECT_TRUE(denied.count(TEST_PERM_1) > 0); +} + +TEST_F(RBACLinkedPermissionsTest, DeniedPermission_OverridesGranted) +{ + // Grant permission, then revoke and deny + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + + rbacData->RevokePermission(TEST_PERM_1); + rbacData->DenyPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); +} + +/** + * @class RBACSecurityLevelTest + * @brief Tests for security level accessor. + */ +class RBACSecurityLevelTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Register a test permission for the test + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Test Permission"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACSecurityLevelTest, Constructor_PreservesSecurityLevel) +{ + rbac::RBACData rbacLevel0(1, "Player", 1, 0); + EXPECT_EQ(rbacLevel0.GetSecurityLevel(), 0); + + rbac::RBACData rbacLevel1(2, "Moderator", 1, 1); + EXPECT_EQ(rbacLevel1.GetSecurityLevel(), 1); + + rbac::RBACData rbacLevel2(3, "GameMaster", 1, 2); + EXPECT_EQ(rbacLevel2.GetSecurityLevel(), 2); + + rbac::RBACData rbacLevel3(4, "Administrator", 1, 3); + EXPECT_EQ(rbacLevel3.GetSecurityLevel(), 3); +} + +TEST_F(RBACSecurityLevelTest, SetSecurityLevelForTest_UpdatesLevel) +{ + rbac::RBACData rbac(1, "TestAccount", 1, 0); + EXPECT_EQ(rbac.GetSecurityLevel(), 0); + + // Use test-friendly setter that doesn't call LoadFromDB + rbac.SetSecurityLevelForTest(3); + EXPECT_EQ(rbac.GetSecurityLevel(), 3); +} + +/** + * @class RBACPermissionExpansionTest + * @brief Tests for permission expansion through linked permissions. + * + * Tests verify that when a role/permission with linked permissions is granted, + * all linked permissions become effective via ExpandPermissions(). + */ +class RBACPermissionExpansionTest : public ::testing::Test +{ +protected: + // Permission structure for testing: + // ROLE_GM (100) -> links to PERM_KICK (10), PERM_BAN (11) + // ROLE_ADMIN (101) -> links to ROLE_GM (100), PERM_SHUTDOWN (12) + // This creates a hierarchy: ADMIN -> GM -> individual permissions + + static constexpr uint32 PERM_KICK = 10; + static constexpr uint32 PERM_BAN = 11; + static constexpr uint32 PERM_SHUTDOWN = 12; + static constexpr uint32 PERM_TELEPORT = 13; + static constexpr uint32 ROLE_GM = 100; + static constexpr uint32 ROLE_ADMIN = 101; + + void SetUp() override + { + // Register individual permissions + sAccountMgr->AddPermissionForTest(PERM_KICK, "Kick Permission"); + sAccountMgr->AddPermissionForTest(PERM_BAN, "Ban Permission"); + sAccountMgr->AddPermissionForTest(PERM_SHUTDOWN, "Shutdown Permission"); + sAccountMgr->AddPermissionForTest(PERM_TELEPORT, "Teleport Permission"); + + // Register role permissions + sAccountMgr->AddPermissionForTest(ROLE_GM, "GameMaster Role"); + sAccountMgr->AddPermissionForTest(ROLE_ADMIN, "Administrator Role"); + + // Set up permission hierarchy: + // GM role includes kick and ban + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_KICK); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_BAN); + + // Admin role includes GM role and shutdown + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, ROLE_GM); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, PERM_SHUTDOWN); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACPermissionExpansionTest, GrantRole_ExpandsLinkedPermissions) +{ + // Grant GM role + rbacData->GrantPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + + // Should have access to GM role and linked permissions (kick, ban) + EXPECT_TRUE(rbacData->HasPermission(ROLE_GM)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_BAN)); + + // Should NOT have access to unlinked permissions + EXPECT_FALSE(rbacData->HasPermission(PERM_SHUTDOWN)); + EXPECT_FALSE(rbacData->HasPermission(PERM_TELEPORT)); +} + +TEST_F(RBACPermissionExpansionTest, GrantRole_RecursiveExpansion) +{ + // Grant Admin role (which links to GM role, which links to kick/ban) + rbacData->GrantPermission(ROLE_ADMIN); + rbacData->RecalculatePermissions(); + + // Should have access to Admin role + EXPECT_TRUE(rbacData->HasPermission(ROLE_ADMIN)); + + // Should have access to directly linked permissions (GM role, shutdown) + EXPECT_TRUE(rbacData->HasPermission(ROLE_GM)); + EXPECT_TRUE(rbacData->HasPermission(PERM_SHUTDOWN)); + + // Should have access to recursively linked permissions (from GM role) + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_BAN)); + + // Should NOT have access to unlinked permissions + EXPECT_FALSE(rbacData->HasPermission(PERM_TELEPORT)); +} + +TEST_F(RBACPermissionExpansionTest, DenyRole_PreventsLinkedPermissions) +{ + // Grant teleport individually + rbacData->GrantPermission(PERM_TELEPORT); + + // Grant admin role (gives kick, ban, shutdown via expansion) + rbacData->GrantPermission(ROLE_ADMIN); + rbacData->RecalculatePermissions(); + + // Verify all permissions are granted + EXPECT_TRUE(rbacData->HasPermission(ROLE_ADMIN)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_TELEPORT)); + + // Now revoke admin and deny the GM role + rbacData->RevokePermission(ROLE_ADMIN); + rbacData->DenyPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + + // GM role and its linked permissions should be denied + EXPECT_FALSE(rbacData->HasPermission(ROLE_GM)); + EXPECT_FALSE(rbacData->HasPermission(PERM_KICK)); + EXPECT_FALSE(rbacData->HasPermission(PERM_BAN)); + + // Teleport was granted directly, not through GM, so should still work + EXPECT_TRUE(rbacData->HasPermission(PERM_TELEPORT)); +} + +TEST_F(RBACPermissionExpansionTest, DenyRole_OverridesIndividualGrant) +{ + // Grant kick permission individually + rbacData->GrantPermission(PERM_KICK); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + + // Deny the GM role (which links to kick) + rbacData->DenyPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + + // Denying a role expands to deny all linked permissions + // Even though kick was granted individually, denying GM role + // expands to deny kick as well (RBAC deny expansion) + EXPECT_FALSE(rbacData->HasPermission(PERM_KICK)); + EXPECT_FALSE(rbacData->HasPermission(ROLE_GM)); + EXPECT_FALSE(rbacData->HasPermission(PERM_BAN)); +} + +/** + * @class RBACDefaultPermissionsTest + * @brief Tests for default permissions based on security level. + * + * Tests verify that default permissions from rbac_default_permissions + * are properly applied based on account security level. + */ +class RBACDefaultPermissionsTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_PLAYER_1 = 20; + static constexpr uint32 PERM_PLAYER_2 = 21; + static constexpr uint32 PERM_MOD_1 = 30; + static constexpr uint32 PERM_GM_1 = 40; + static constexpr uint32 PERM_ADMIN_1 = 50; + + static constexpr uint8 SEC_PLAYER = 0; + static constexpr uint8 SEC_MODERATOR = 1; + static constexpr uint8 SEC_GAMEMASTER = 2; + static constexpr uint8 SEC_ADMINISTRATOR = 3; + + void SetUp() override + { + // Register test permissions + sAccountMgr->AddPermissionForTest(PERM_PLAYER_1, "Player Permission 1"); + sAccountMgr->AddPermissionForTest(PERM_PLAYER_2, "Player Permission 2"); + sAccountMgr->AddPermissionForTest(PERM_MOD_1, "Moderator Permission 1"); + sAccountMgr->AddPermissionForTest(PERM_GM_1, "GameMaster Permission 1"); + sAccountMgr->AddPermissionForTest(PERM_ADMIN_1, "Administrator Permission 1"); + + // Set up default permissions for security levels + sAccountMgr->AddDefaultPermissionForTest(SEC_PLAYER, PERM_PLAYER_1); + sAccountMgr->AddDefaultPermissionForTest(SEC_PLAYER, PERM_PLAYER_2); + + sAccountMgr->AddDefaultPermissionForTest(SEC_MODERATOR, PERM_MOD_1); + + sAccountMgr->AddDefaultPermissionForTest(SEC_GAMEMASTER, PERM_GM_1); + + sAccountMgr->AddDefaultPermissionForTest(SEC_ADMINISTRATOR, PERM_ADMIN_1); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACDefaultPermissionsTest, GetDefaultPermissions_ReturnsCorrectSet) +{ + rbac::RBACPermissionContainer const& playerPerms = sAccountMgr->GetRBACDefaultPermissions(SEC_PLAYER); + EXPECT_EQ(playerPerms.size(), 2u); + EXPECT_TRUE(playerPerms.count(PERM_PLAYER_1) > 0); + EXPECT_TRUE(playerPerms.count(PERM_PLAYER_2) > 0); + + rbac::RBACPermissionContainer const& modPerms = sAccountMgr->GetRBACDefaultPermissions(SEC_MODERATOR); + EXPECT_EQ(modPerms.size(), 1u); + EXPECT_TRUE(modPerms.count(PERM_MOD_1) > 0); + + rbac::RBACPermissionContainer const& gmPerms = sAccountMgr->GetRBACDefaultPermissions(SEC_GAMEMASTER); + EXPECT_EQ(gmPerms.size(), 1u); + EXPECT_TRUE(gmPerms.count(PERM_GM_1) > 0); + + rbac::RBACPermissionContainer const& adminPerms = sAccountMgr->GetRBACDefaultPermissions(SEC_ADMINISTRATOR); + EXPECT_EQ(adminPerms.size(), 1u); + EXPECT_TRUE(adminPerms.count(PERM_ADMIN_1) > 0); +} + +TEST_F(RBACDefaultPermissionsTest, GetDefaultPermissions_EmptySecLevel_ReturnsEmpty) +{ + // Security level 255 has no default permissions set + rbac::RBACPermissionContainer const& emptyPerms = sAccountMgr->GetRBACDefaultPermissions(255); + EXPECT_TRUE(emptyPerms.empty()); +} + +TEST_F(RBACDefaultPermissionsTest, SecurityLevel_DeterminesDefaultPermissions) +{ + // Create RBACData for a player account (sec level 0) + rbac::RBACData playerData(1, "PlayerAccount", TEST_REALM_ID, SEC_PLAYER); + + // Manually grant the default permissions (simulating LoadFromDBCallback) + rbac::RBACPermissionContainer const& playerDefaults = sAccountMgr->GetRBACDefaultPermissions(SEC_PLAYER); + for (uint32 perm : playerDefaults) + playerData.GrantPermission(perm); + + playerData.RecalculatePermissions(); + + // Player should have player permissions + EXPECT_TRUE(playerData.HasPermission(PERM_PLAYER_1)); + EXPECT_TRUE(playerData.HasPermission(PERM_PLAYER_2)); + + // Player should NOT have higher level permissions + EXPECT_FALSE(playerData.HasPermission(PERM_MOD_1)); + EXPECT_FALSE(playerData.HasPermission(PERM_GM_1)); + EXPECT_FALSE(playerData.HasPermission(PERM_ADMIN_1)); +} + +TEST_F(RBACDefaultPermissionsTest, HigherSecLevel_GetsOnlyOwnDefaults) +{ + // Create RBACData for an admin account (sec level 3) + rbac::RBACData adminData(4, "AdminAccount", TEST_REALM_ID, SEC_ADMINISTRATOR); + + // Manually grant the default permissions for admin level + rbac::RBACPermissionContainer const& adminDefaults = sAccountMgr->GetRBACDefaultPermissions(SEC_ADMINISTRATOR); + for (uint32 perm : adminDefaults) + adminData.GrantPermission(perm); + + adminData.RecalculatePermissions(); + + // Admin gets their own default permissions + EXPECT_TRUE(adminData.HasPermission(PERM_ADMIN_1)); + + // Note: In a real setup, admin would typically have a role that links to + // lower permissions. Here we're just testing that default permissions + // are applied per security level, not inherited. + // Without explicit roles linking them, admin doesn't automatically get + // player/mod/gm permissions. + EXPECT_FALSE(adminData.HasPermission(PERM_PLAYER_1)); + EXPECT_FALSE(adminData.HasPermission(PERM_MOD_1)); + EXPECT_FALSE(adminData.HasPermission(PERM_GM_1)); +} + +/** + * @class RBACDeniedExpansionTest + * @brief Tests for denied permission expansion. + * + * Tests verify that denied permissions are properly expanded + * and remove access to linked permissions. + */ +class RBACDeniedExpansionTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_KICK = 10; + static constexpr uint32 PERM_BAN = 11; + static constexpr uint32 ROLE_GM = 100; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_KICK, "Kick Permission"); + sAccountMgr->AddPermissionForTest(PERM_BAN, "Ban Permission"); + sAccountMgr->AddPermissionForTest(ROLE_GM, "GameMaster Role"); + + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_KICK); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_BAN); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACDeniedExpansionTest, DenyRole_ExpandsDeniedLinkedPermissions) +{ + // First grant individual permissions that would be linked from GM + rbacData->GrantPermission(PERM_KICK); + rbacData->GrantPermission(PERM_BAN); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_BAN)); + + // Now deny the GM role + rbacData->DenyPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + + // The GM role and its linked permissions should be denied + // Even though kick/ban were granted individually, denying the role + // that links them should expand to deny those permissions + EXPECT_FALSE(rbacData->HasPermission(ROLE_GM)); + EXPECT_FALSE(rbacData->HasPermission(PERM_KICK)); + EXPECT_FALSE(rbacData->HasPermission(PERM_BAN)); +} + +TEST_F(RBACDeniedExpansionTest, GrantAndDenySameRole_DenyWins) +{ + // Grant the GM role + rbacData->GrantPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(ROLE_GM)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + + // Revoke and then deny + rbacData->RevokePermission(ROLE_GM); + rbacData->DenyPermission(ROLE_GM); + rbacData->RecalculatePermissions(); + + // Deny should win - no access + EXPECT_FALSE(rbacData->HasPermission(ROLE_GM)); + EXPECT_FALSE(rbacData->HasPermission(PERM_KICK)); + EXPECT_FALSE(rbacData->HasPermission(PERM_BAN)); +} + +// --------------------------------------------------------------------------- +// Suite 1: RBACPermissionRemoveLinkedTest +// --------------------------------------------------------------------------- +class RBACPermissionRemoveLinkedTest : public ::testing::Test +{ +protected: + void SetUp() override + { + permission = std::make_unique(TEST_PERM_1, "Test Permission"); + permission->AddLinkedPermission(TEST_PERM_2); + permission->AddLinkedPermission(TEST_PERM_3); + } + + std::unique_ptr permission; +}; + +TEST_F(RBACPermissionRemoveLinkedTest, RemoveLinkedPermission_RemovesFromSet) +{ + EXPECT_EQ(permission->GetLinkedPermissions().size(), 2u); + permission->RemoveLinkedPermission(TEST_PERM_2); + EXPECT_EQ(permission->GetLinkedPermissions().size(), 1u); + EXPECT_EQ(permission->GetLinkedPermissions().count(TEST_PERM_2), 0u); + EXPECT_EQ(permission->GetLinkedPermissions().count(TEST_PERM_3), 1u); +} + +TEST_F(RBACPermissionRemoveLinkedTest, RemoveNonExistent_IsNoOp) +{ + permission->RemoveLinkedPermission(TEST_PERM_INVALID); + EXPECT_EQ(permission->GetLinkedPermissions().size(), 2u); +} + +TEST_F(RBACPermissionRemoveLinkedTest, RemoveAll_LeavesEmpty) +{ + permission->RemoveLinkedPermission(TEST_PERM_2); + permission->RemoveLinkedPermission(TEST_PERM_3); + EXPECT_TRUE(permission->GetLinkedPermissions().empty()); +} + +// --------------------------------------------------------------------------- +// Suite 2: RBACGetPermissionsTest (computed global perms) +// --------------------------------------------------------------------------- +class RBACGetPermissionsTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_A = 10; + static constexpr uint32 PERM_B = 11; + static constexpr uint32 PERM_C = 12; + static constexpr uint32 ROLE_R = 100; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_A, "Permission A"); + sAccountMgr->AddPermissionForTest(PERM_B, "Permission B"); + sAccountMgr->AddPermissionForTest(PERM_C, "Permission C"); + sAccountMgr->AddPermissionForTest(ROLE_R, "Role R"); + + sAccountMgr->AddLinkedPermissionForTest(ROLE_R, PERM_A); + sAccountMgr->AddLinkedPermissionForTest(ROLE_R, PERM_B); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACGetPermissionsTest, Empty_WhenNothingGranted) +{ + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->GetPermissions().empty()); +} + +TEST_F(RBACGetPermissionsTest, MatchesHasPermission) +{ + rbacData->GrantPermission(PERM_A); + rbacData->GrantPermission(PERM_C); + rbacData->RecalculatePermissions(); + + auto const& perms = rbacData->GetPermissions(); + for (uint32 p : perms) + EXPECT_TRUE(rbacData->HasPermission(p)); + EXPECT_FALSE(rbacData->HasPermission(PERM_B)); +} + +TEST_F(RBACGetPermissionsTest, ExcludesDeniedPermissions) +{ + rbacData->GrantPermission(PERM_A); + rbacData->GrantPermission(PERM_C); + rbacData->DenyPermission(PERM_B); + rbacData->RecalculatePermissions(); + + auto const& perms = rbacData->GetPermissions(); + EXPECT_TRUE(perms.count(PERM_A) > 0); + EXPECT_TRUE(perms.count(PERM_C) > 0); + EXPECT_EQ(perms.count(PERM_B), 0u); +} + +TEST_F(RBACGetPermissionsTest, IncludesExpandedLinkedPermissions) +{ + rbacData->GrantPermission(ROLE_R); + rbacData->RecalculatePermissions(); + + auto const& perms = rbacData->GetPermissions(); + EXPECT_TRUE(perms.count(ROLE_R) > 0); + EXPECT_TRUE(perms.count(PERM_A) > 0); + EXPECT_TRUE(perms.count(PERM_B) > 0); + EXPECT_EQ(perms.count(PERM_C), 0u); +} + +TEST_F(RBACGetPermissionsTest, ReflectsStateAfterRecalculate) +{ + rbacData->GrantPermission(PERM_A); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->GetPermissions().count(PERM_A) > 0); + + rbacData->RevokePermission(PERM_A); + rbacData->RecalculatePermissions(); + EXPECT_EQ(rbacData->GetPermissions().count(PERM_A), 0u); +} + +// --------------------------------------------------------------------------- +// Suite 3: RBACRevokeEdgeCasesTest +// --------------------------------------------------------------------------- +class RBACRevokeEdgeCasesTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Permission 2"); + sAccountMgr->AddPermissionForTest(TEST_PERM_3, "Permission 3"); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACRevokeEdgeCasesTest, RevokeUnregistered_ReturnsCantRevoke) +{ + rbac::RBACCommandResult result = rbacData->RevokePermission(TEST_PERM_INVALID); + EXPECT_EQ(result, rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); +} + +TEST_F(RBACRevokeEdgeCasesTest, RevokeFromEmpty_ReturnsError) +{ + rbac::RBACCommandResult result = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); +} + +TEST_F(RBACRevokeEdgeCasesTest, RevokeGranted_ThenDeny) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + + rbacData->RevokePermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + EXPECT_TRUE(rbacData->GetDeniedPermissions().count(TEST_PERM_1) > 0); +} + +TEST_F(RBACRevokeEdgeCasesTest, RevokeDenied_ThenGrant) +{ + rbacData->DenyPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + + rbacData->RevokePermission(TEST_PERM_1); + rbac::RBACCommandResult result = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(result, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACRevokeEdgeCasesTest, RevokeDoesNotAffectOtherPermissions) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->GrantPermission(TEST_PERM_2); + rbacData->DenyPermission(TEST_PERM_3); + + rbacData->RevokePermission(TEST_PERM_1); + + EXPECT_TRUE(rbacData->GetGrantedPermissions().count(TEST_PERM_2) > 0); + EXPECT_TRUE(rbacData->GetDeniedPermissions().count(TEST_PERM_3) > 0); + EXPECT_EQ(rbacData->GetGrantedPermissions().count(TEST_PERM_1), 0u); +} + +// --------------------------------------------------------------------------- +// Suite 4: RBACComplexHierarchyTest +// --------------------------------------------------------------------------- +class RBACComplexHierarchyTest : public ::testing::Test +{ +protected: + // 3-level: Admin(100)->GM(101)->Mod(102)->individual perms + static constexpr uint32 PERM_A = 10; + static constexpr uint32 PERM_B = 11; + static constexpr uint32 PERM_C = 12; + static constexpr uint32 PERM_D = 13; + static constexpr uint32 PERM_E = 14; + static constexpr uint32 PERM_F = 15; + static constexpr uint32 PERM_G = 16; + static constexpr uint32 PERM_H = 17; + static constexpr uint32 PERM_I = 18; + static constexpr uint32 PERM_J = 19; + static constexpr uint32 PERM_K = 20; + static constexpr uint32 PERM_L = 21; + static constexpr uint32 ROLE_MOD = 102; + static constexpr uint32 ROLE_GM = 101; + static constexpr uint32 ROLE_ADMIN = 100; + // Diamond: ROLE_X(103) and ROLE_Y(104) both link to PERM_SHARED(22) + static constexpr uint32 PERM_SHARED = 22; + static constexpr uint32 PERM_X_ONLY = 23; + static constexpr uint32 PERM_Y_ONLY = 24; + static constexpr uint32 ROLE_X = 103; + static constexpr uint32 ROLE_Y = 104; + // Wide role + static constexpr uint32 ROLE_WIDE = 105; + + void SetUp() override + { + // Register individual perms + sAccountMgr->AddPermissionForTest(PERM_A, "A"); + sAccountMgr->AddPermissionForTest(PERM_B, "B"); + sAccountMgr->AddPermissionForTest(PERM_C, "C"); + sAccountMgr->AddPermissionForTest(PERM_D, "D"); + sAccountMgr->AddPermissionForTest(PERM_E, "E"); + sAccountMgr->AddPermissionForTest(PERM_F, "F"); + sAccountMgr->AddPermissionForTest(PERM_G, "G"); + sAccountMgr->AddPermissionForTest(PERM_H, "H"); + sAccountMgr->AddPermissionForTest(PERM_I, "I"); + sAccountMgr->AddPermissionForTest(PERM_J, "J"); + sAccountMgr->AddPermissionForTest(PERM_K, "K"); + sAccountMgr->AddPermissionForTest(PERM_L, "L"); + sAccountMgr->AddPermissionForTest(PERM_SHARED, "Shared"); + sAccountMgr->AddPermissionForTest(PERM_X_ONLY, "X Only"); + sAccountMgr->AddPermissionForTest(PERM_Y_ONLY, "Y Only"); + + // Register roles + sAccountMgr->AddPermissionForTest(ROLE_MOD, "Mod"); + sAccountMgr->AddPermissionForTest(ROLE_GM, "GM"); + sAccountMgr->AddPermissionForTest(ROLE_ADMIN, "Admin"); + sAccountMgr->AddPermissionForTest(ROLE_X, "X"); + sAccountMgr->AddPermissionForTest(ROLE_Y, "Y"); + sAccountMgr->AddPermissionForTest(ROLE_WIDE, "Wide"); + + // 3-level hierarchy + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_A); + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_B); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, ROLE_MOD); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_C); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, ROLE_GM); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, PERM_D); + + // Diamond inheritance + sAccountMgr->AddLinkedPermissionForTest(ROLE_X, PERM_SHARED); + sAccountMgr->AddLinkedPermissionForTest(ROLE_X, PERM_X_ONLY); + sAccountMgr->AddLinkedPermissionForTest(ROLE_Y, PERM_SHARED); + sAccountMgr->AddLinkedPermissionForTest(ROLE_Y, PERM_Y_ONLY); + + // Wide role (10+ linked perms) + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_A); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_B); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_C); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_D); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_E); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_F); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_G); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_H); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_I); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_J); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_K); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WIDE, PERM_L); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACComplexHierarchyTest, ThreeLevelDeep) +{ + rbacData->GrantPermission(ROLE_ADMIN); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(ROLE_ADMIN)); + EXPECT_TRUE(rbacData->HasPermission(ROLE_GM)); + EXPECT_TRUE(rbacData->HasPermission(ROLE_MOD)); + EXPECT_TRUE(rbacData->HasPermission(PERM_A)); + EXPECT_TRUE(rbacData->HasPermission(PERM_B)); + EXPECT_TRUE(rbacData->HasPermission(PERM_C)); + EXPECT_TRUE(rbacData->HasPermission(PERM_D)); +} + +TEST_F(RBACComplexHierarchyTest, DiamondInheritance) +{ + rbacData->GrantPermission(ROLE_X); + rbacData->GrantPermission(ROLE_Y); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(PERM_SHARED)); + EXPECT_TRUE(rbacData->HasPermission(PERM_X_ONLY)); + EXPECT_TRUE(rbacData->HasPermission(PERM_Y_ONLY)); +} + +TEST_F(RBACComplexHierarchyTest, WideRole) +{ + rbacData->GrantPermission(ROLE_WIDE); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(ROLE_WIDE)); + EXPECT_TRUE(rbacData->HasPermission(PERM_A)); + EXPECT_TRUE(rbacData->HasPermission(PERM_L)); + EXPECT_EQ(rbacData->GetPermissions().size(), 13u); // ROLE_WIDE + 12 perms +} + +TEST_F(RBACComplexHierarchyTest, TwoOverlappingRoles_NoDuplicateInGetPermissions) +{ + // Both ROLE_X and ROLE_Y link to PERM_SHARED + rbacData->GrantPermission(ROLE_X); + rbacData->GrantPermission(ROLE_Y); + rbacData->RecalculatePermissions(); + + auto const& perms = rbacData->GetPermissions(); + // ROLE_X, ROLE_Y, PERM_SHARED, PERM_X_ONLY, PERM_Y_ONLY = 5 + EXPECT_EQ(perms.size(), 5u); + EXPECT_EQ(perms.count(PERM_SHARED), 1u); +} + +TEST_F(RBACComplexHierarchyTest, RevokeOneOverlappingRole_KeepsSharedFromOther) +{ + rbacData->GrantPermission(ROLE_X); + rbacData->GrantPermission(ROLE_Y); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(PERM_SHARED)); + + rbacData->RevokePermission(ROLE_X); + rbacData->RecalculatePermissions(); + + // PERM_SHARED still accessible through ROLE_Y + EXPECT_TRUE(rbacData->HasPermission(PERM_SHARED)); + EXPECT_TRUE(rbacData->HasPermission(PERM_Y_ONLY)); + EXPECT_FALSE(rbacData->HasPermission(PERM_X_ONLY)); +} + +// --------------------------------------------------------------------------- +// Suite 5: RBACDenySpecificFromRoleTest +// --------------------------------------------------------------------------- +class RBACDenySpecificFromRoleTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_KICK = 10; + static constexpr uint32 PERM_BAN = 11; + static constexpr uint32 PERM_MUTE = 12; + static constexpr uint32 PERM_SHUTDOWN = 13; + static constexpr uint32 ROLE_MOD = 100; + static constexpr uint32 ROLE_ADMIN = 101; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_KICK, "Kick"); + sAccountMgr->AddPermissionForTest(PERM_BAN, "Ban"); + sAccountMgr->AddPermissionForTest(PERM_MUTE, "Mute"); + sAccountMgr->AddPermissionForTest(PERM_SHUTDOWN, "Shutdown"); + sAccountMgr->AddPermissionForTest(ROLE_MOD, "Moderator"); + sAccountMgr->AddPermissionForTest(ROLE_ADMIN, "Admin"); + + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_KICK); + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_BAN); + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_MUTE); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, PERM_SHUTDOWN); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACDenySpecificFromRoleTest, DenyOneChild_SiblingsStillGranted) +{ + rbacData->GrantPermission(ROLE_MOD); + rbacData->DenyPermission(PERM_BAN); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(ROLE_MOD)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_MUTE)); + EXPECT_FALSE(rbacData->HasPermission(PERM_BAN)); +} + +TEST_F(RBACDenySpecificFromRoleTest, DenyPermNotInRole_RolePermsUnaffected) +{ + rbacData->GrantPermission(ROLE_MOD); + rbacData->DenyPermission(PERM_SHUTDOWN); + rbacData->RecalculatePermissions(); + + EXPECT_TRUE(rbacData->HasPermission(ROLE_MOD)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_BAN)); + EXPECT_TRUE(rbacData->HasPermission(PERM_MUTE)); + EXPECT_FALSE(rbacData->HasPermission(PERM_SHUTDOWN)); +} + +TEST_F(RBACDenySpecificFromRoleTest, GrantTwoRoles_DenyOneRole) +{ + rbacData->GrantPermission(ROLE_MOD); + rbacData->GrantPermission(ROLE_ADMIN); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(PERM_SHUTDOWN)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + + // Revoke and deny ROLE_ADMIN + rbacData->RevokePermission(ROLE_ADMIN); + rbacData->DenyPermission(ROLE_ADMIN); + rbacData->RecalculatePermissions(); + + // ROLE_ADMIN and its unique perm (SHUTDOWN) denied + EXPECT_FALSE(rbacData->HasPermission(ROLE_ADMIN)); + EXPECT_FALSE(rbacData->HasPermission(PERM_SHUTDOWN)); + + // ROLE_MOD perms remain + EXPECT_TRUE(rbacData->HasPermission(ROLE_MOD)); + EXPECT_TRUE(rbacData->HasPermission(PERM_KICK)); + EXPECT_TRUE(rbacData->HasPermission(PERM_BAN)); + EXPECT_TRUE(rbacData->HasPermission(PERM_MUTE)); +} + +// --------------------------------------------------------------------------- +// Suite 6: RBACDefaultPermissionsWithRolesTest +// --------------------------------------------------------------------------- +class RBACDefaultPermissionsWithRolesTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_A = 10; + static constexpr uint32 PERM_B = 11; + static constexpr uint32 PERM_C = 12; + static constexpr uint32 PERM_MOD_1 = 13; + static constexpr uint32 ROLE_PLAYER = 100; + + static constexpr uint8 SEC_PLAYER = 0; + static constexpr uint8 SEC_MODERATOR = 1; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_A, "A"); + sAccountMgr->AddPermissionForTest(PERM_B, "B"); + sAccountMgr->AddPermissionForTest(PERM_C, "C"); + sAccountMgr->AddPermissionForTest(PERM_MOD_1, "Mod 1"); + sAccountMgr->AddPermissionForTest(ROLE_PLAYER, "Player Role"); + + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_A); + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_B); + + // Default: Player gets ROLE_PLAYER, Moderator gets PERM_MOD_1 + sAccountMgr->AddDefaultPermissionForTest(SEC_PLAYER, ROLE_PLAYER); + sAccountMgr->AddDefaultPermissionForTest(SEC_MODERATOR, PERM_MOD_1); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACDefaultPermissionsWithRolesTest, DefaultRoleExpandsLinked) +{ + rbac::RBACData data(1, "Player", TEST_REALM_ID, SEC_PLAYER); + + // Simulate LoadFromDBCallback: grant defaults then recalculate + rbac::RBACPermissionContainer const& defaults = sAccountMgr->GetRBACDefaultPermissions(SEC_PLAYER); + for (uint32 perm : defaults) + data.GrantPermission(perm); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_TRUE(data.HasPermission(PERM_B)); +} + +TEST_F(RBACDefaultPermissionsWithRolesTest, DefaultRole_DenyLinkedChild) +{ + rbac::RBACData data(1, "Player", TEST_REALM_ID, SEC_PLAYER); + + rbac::RBACPermissionContainer const& defaults = sAccountMgr->GetRBACDefaultPermissions(SEC_PLAYER); + for (uint32 perm : defaults) + data.GrantPermission(perm); + + data.DenyPermission(PERM_B); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_FALSE(data.HasPermission(PERM_B)); +} + +TEST_F(RBACDefaultPermissionsWithRolesTest, SecLevels_NoCrossContamination) +{ + rbac::RBACData playerData(1, "Player", TEST_REALM_ID, SEC_PLAYER); + rbac::RBACData modData(2, "Mod", TEST_REALM_ID, SEC_MODERATOR); + + // Grant defaults for each + for (uint32 p : sAccountMgr->GetRBACDefaultPermissions(SEC_PLAYER)) + playerData.GrantPermission(p); + playerData.RecalculatePermissions(); + + for (uint32 p : sAccountMgr->GetRBACDefaultPermissions(SEC_MODERATOR)) + modData.GrantPermission(p); + modData.RecalculatePermissions(); + + // Player has player perms, not mod perms + EXPECT_TRUE(playerData.HasPermission(PERM_A)); + EXPECT_FALSE(playerData.HasPermission(PERM_MOD_1)); + + // Mod has mod perms, not player perms (unless explicitly granted) + EXPECT_TRUE(modData.HasPermission(PERM_MOD_1)); + EXPECT_FALSE(modData.HasPermission(PERM_A)); +} + +// --------------------------------------------------------------------------- +// Suite 7: RBACPermissionEnumConsistencyTest +// --------------------------------------------------------------------------- +class RBACPermissionEnumConsistencyTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(500, "Perm 500"); + sAccountMgr->AddPermissionForTest(700, "Perm 700"); + sAccountMgr->AddPermissionForTest(900, "Perm 900"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACPermissionEnumConsistencyTest, MaxGreaterThanHighestDefined) +{ + EXPECT_GT(static_cast(rbac::RBAC_PERM_MAX), 911u); +} + +TEST_F(RBACPermissionEnumConsistencyTest, RoleIdsWithinRange) +{ + EXPECT_LT(static_cast(rbac::RBAC_ROLE_ADMINISTRATOR), static_cast(rbac::RBAC_PERM_MAX)); + EXPECT_LT(static_cast(rbac::RBAC_ROLE_GAMEMASTER), static_cast(rbac::RBAC_PERM_MAX)); + EXPECT_LT(static_cast(rbac::RBAC_ROLE_MODERATOR), static_cast(rbac::RBAC_PERM_MAX)); + EXPECT_LT(static_cast(rbac::RBAC_ROLE_PLAYER), static_cast(rbac::RBAC_PERM_MAX)); +} + +TEST_F(RBACPermissionEnumConsistencyTest, NonContiguousIds_Work) +{ + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + + data.GrantPermission(500); + data.GrantPermission(900); + data.DenyPermission(700); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(500)); + EXPECT_TRUE(data.HasPermission(900)); + EXPECT_FALSE(data.HasPermission(700)); +} + +// --------------------------------------------------------------------------- +// Suite 8: RBACEmptyAndBoundaryTest +// --------------------------------------------------------------------------- +class RBACEmptyAndBoundaryTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACEmptyAndBoundaryTest, FreshData_AllEmpty) +{ + EXPECT_TRUE(rbacData->GetGrantedPermissions().empty()); + EXPECT_TRUE(rbacData->GetDeniedPermissions().empty()); + EXPECT_TRUE(rbacData->GetPermissions().empty()); +} + +TEST_F(RBACEmptyAndBoundaryTest, HasPermission_Zero_ReturnsFalse) +{ + EXPECT_FALSE(rbacData->HasPermission(0)); +} + +TEST_F(RBACEmptyAndBoundaryTest, HasPermission_Max_ReturnsFalse) +{ + EXPECT_FALSE(rbacData->HasPermission(rbac::RBAC_PERM_MAX)); +} + +TEST_F(RBACEmptyAndBoundaryTest, GrantDenyRevokeSequence) +{ + rbac::RBACCommandResult r1 = rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(r1, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(TEST_PERM_1)); + + rbac::RBACCommandResult r2 = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(r2, rbac::RBAC_OK); + + rbac::RBACCommandResult r3 = rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(r3, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); + + rbac::RBACCommandResult r4 = rbacData->RevokePermission(TEST_PERM_1); + EXPECT_EQ(r4, rbac::RBAC_OK); + rbacData->RecalculatePermissions(); + EXPECT_FALSE(rbacData->HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACEmptyAndBoundaryTest, MultipleRecalculates_Idempotent) +{ + rbacData->GrantPermission(TEST_PERM_1); + rbacData->RecalculatePermissions(); + auto perms1 = rbacData->GetPermissions(); + + rbacData->RecalculatePermissions(); + auto perms2 = rbacData->GetPermissions(); + + rbacData->RecalculatePermissions(); + auto perms3 = rbacData->GetPermissions(); + + EXPECT_EQ(perms1, perms2); + EXPECT_EQ(perms2, perms3); +} + +TEST_F(RBACEmptyAndBoundaryTest, RecalculateOnEmpty_Safe) +{ + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->GetPermissions().empty()); + + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->GetPermissions().empty()); +} + +// --------------------------------------------------------------------------- +// Suite 9: RBACCircularLinkProtectionTest +// --------------------------------------------------------------------------- +class RBACCircularLinkProtectionTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_A = 10; + static constexpr uint32 PERM_B = 11; + static constexpr uint32 PERM_C = 12; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_A, "A"); + sAccountMgr->AddPermissionForTest(PERM_B, "B"); + sAccountMgr->AddPermissionForTest(PERM_C, "C"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACCircularLinkProtectionTest, MutualLink_BothGranted) +{ + sAccountMgr->AddLinkedPermissionForTest(PERM_A, PERM_B); + sAccountMgr->AddLinkedPermissionForTest(PERM_B, PERM_A); + + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + data.GrantPermission(PERM_A); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_TRUE(data.HasPermission(PERM_B)); +} + +TEST_F(RBACCircularLinkProtectionTest, SelfReferencing_Terminates) +{ + sAccountMgr->AddLinkedPermissionForTest(PERM_A, PERM_A); + + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + data.GrantPermission(PERM_A); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_EQ(data.GetPermissions().size(), 1u); +} + +TEST_F(RBACCircularLinkProtectionTest, CircularChainOf3_AllGranted) +{ + sAccountMgr->AddLinkedPermissionForTest(PERM_A, PERM_B); + sAccountMgr->AddLinkedPermissionForTest(PERM_B, PERM_C); + sAccountMgr->AddLinkedPermissionForTest(PERM_C, PERM_A); + + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + data.GrantPermission(PERM_A); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_TRUE(data.HasPermission(PERM_B)); + EXPECT_TRUE(data.HasPermission(PERM_C)); + EXPECT_EQ(data.GetPermissions().size(), 3u); +} + +// --------------------------------------------------------------------------- +// Suite 10: RBACFullRoleHierarchyTest (mirrors actual 192-199 structure) +// --------------------------------------------------------------------------- +class RBACFullRoleHierarchyTest : public ::testing::Test +{ +protected: + // Roles + static constexpr uint32 ROLE_PLAYER = 199; + static constexpr uint32 ROLE_MOD = 198; + static constexpr uint32 ROLE_GM = 197; + static constexpr uint32 ROLE_ADMIN = 196; + + // Individual perms + static constexpr uint32 PERM_PLAYER_1 = 10; + static constexpr uint32 PERM_PLAYER_2 = 11; + static constexpr uint32 PERM_MOD_1 = 20; + static constexpr uint32 PERM_MOD_2 = 21; + static constexpr uint32 PERM_GM_1 = 30; + static constexpr uint32 PERM_GM_2 = 31; + static constexpr uint32 PERM_ADMIN_1 = 40; + static constexpr uint32 PERM_ADMIN_2 = 41; + + void SetUp() override + { + // Register individual perms + sAccountMgr->AddPermissionForTest(PERM_PLAYER_1, "Player 1"); + sAccountMgr->AddPermissionForTest(PERM_PLAYER_2, "Player 2"); + sAccountMgr->AddPermissionForTest(PERM_MOD_1, "Mod 1"); + sAccountMgr->AddPermissionForTest(PERM_MOD_2, "Mod 2"); + sAccountMgr->AddPermissionForTest(PERM_GM_1, "GM 1"); + sAccountMgr->AddPermissionForTest(PERM_GM_2, "GM 2"); + sAccountMgr->AddPermissionForTest(PERM_ADMIN_1, "Admin 1"); + sAccountMgr->AddPermissionForTest(PERM_ADMIN_2, "Admin 2"); + + // Register roles + sAccountMgr->AddPermissionForTest(ROLE_PLAYER, "Player Role"); + sAccountMgr->AddPermissionForTest(ROLE_MOD, "Moderator Role"); + sAccountMgr->AddPermissionForTest(ROLE_GM, "GameMaster Role"); + sAccountMgr->AddPermissionForTest(ROLE_ADMIN, "Administrator Role"); + + // Player(199) -> basic perms + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_PLAYER_1); + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_PLAYER_2); + + // Mod(198) -> Player + mod perms + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, ROLE_PLAYER); + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_MOD_1); + sAccountMgr->AddLinkedPermissionForTest(ROLE_MOD, PERM_MOD_2); + + // GM(197) -> Mod + gm perms + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, ROLE_MOD); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_GM_1); + sAccountMgr->AddLinkedPermissionForTest(ROLE_GM, PERM_GM_2); + + // Admin(196) -> GM + admin perms + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, ROLE_GM); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, PERM_ADMIN_1); + sAccountMgr->AddLinkedPermissionForTest(ROLE_ADMIN, PERM_ADMIN_2); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACFullRoleHierarchyTest, GrantPlayerRole_OnlyPlayerPerms) +{ + rbac::RBACData data(1, "Player", TEST_REALM_ID, 0); + data.GrantPermission(ROLE_PLAYER); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_1)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_2)); + + EXPECT_FALSE(data.HasPermission(PERM_MOD_1)); + EXPECT_FALSE(data.HasPermission(PERM_GM_1)); + EXPECT_FALSE(data.HasPermission(PERM_ADMIN_1)); + // 3 total: ROLE_PLAYER + 2 player perms + EXPECT_EQ(data.GetPermissions().size(), 3u); +} + +TEST_F(RBACFullRoleHierarchyTest, GrantGMRole_FullChain) +{ + rbac::RBACData data(1, "GM", TEST_REALM_ID, 0); + data.GrantPermission(ROLE_GM); + data.RecalculatePermissions(); + + // GM + Mod + Player perms + EXPECT_TRUE(data.HasPermission(ROLE_GM)); + EXPECT_TRUE(data.HasPermission(ROLE_MOD)); + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_1)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_2)); + EXPECT_TRUE(data.HasPermission(PERM_MOD_1)); + EXPECT_TRUE(data.HasPermission(PERM_MOD_2)); + EXPECT_TRUE(data.HasPermission(PERM_GM_1)); + EXPECT_TRUE(data.HasPermission(PERM_GM_2)); + + EXPECT_FALSE(data.HasPermission(PERM_ADMIN_1)); + EXPECT_FALSE(data.HasPermission(PERM_ADMIN_2)); + // 9 total: 3 roles + 6 perms + EXPECT_EQ(data.GetPermissions().size(), 9u); +} + +TEST_F(RBACFullRoleHierarchyTest, GrantAdminRole_AllPerms) +{ + rbac::RBACData data(1, "Admin", TEST_REALM_ID, 0); + data.GrantPermission(ROLE_ADMIN); + data.RecalculatePermissions(); + + EXPECT_TRUE(data.HasPermission(ROLE_ADMIN)); + EXPECT_TRUE(data.HasPermission(ROLE_GM)); + EXPECT_TRUE(data.HasPermission(ROLE_MOD)); + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_1)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_2)); + EXPECT_TRUE(data.HasPermission(PERM_MOD_1)); + EXPECT_TRUE(data.HasPermission(PERM_MOD_2)); + EXPECT_TRUE(data.HasPermission(PERM_GM_1)); + EXPECT_TRUE(data.HasPermission(PERM_GM_2)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_1)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_2)); + // 12 total: 4 roles + 8 perms + EXPECT_EQ(data.GetPermissions().size(), 12u); +} + +TEST_F(RBACFullRoleHierarchyTest, GrantAdmin_DenyModRole_ModAndPlayerDenied) +{ + rbac::RBACData data(1, "Admin", TEST_REALM_ID, 0); + data.GrantPermission(ROLE_ADMIN); + data.DenyPermission(ROLE_MOD); + data.RecalculatePermissions(); + + // Admin + GM perms remain + EXPECT_TRUE(data.HasPermission(ROLE_ADMIN)); + EXPECT_TRUE(data.HasPermission(ROLE_GM)); + EXPECT_TRUE(data.HasPermission(PERM_GM_1)); + EXPECT_TRUE(data.HasPermission(PERM_GM_2)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_1)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_2)); + + // Mod role and its full chain denied (Mod + Player perms) + EXPECT_FALSE(data.HasPermission(ROLE_MOD)); + EXPECT_FALSE(data.HasPermission(ROLE_PLAYER)); + EXPECT_FALSE(data.HasPermission(PERM_MOD_1)); + EXPECT_FALSE(data.HasPermission(PERM_MOD_2)); + EXPECT_FALSE(data.HasPermission(PERM_PLAYER_1)); + EXPECT_FALSE(data.HasPermission(PERM_PLAYER_2)); +} + +TEST_F(RBACFullRoleHierarchyTest, GrantAdmin_DenyOneCommandPerm) +{ + rbac::RBACData data(1, "Admin", TEST_REALM_ID, 0); + data.GrantPermission(ROLE_ADMIN); + data.DenyPermission(PERM_GM_1); + data.RecalculatePermissions(); + + // Only PERM_GM_1 is denied + EXPECT_FALSE(data.HasPermission(PERM_GM_1)); + + // Everything else still works + EXPECT_TRUE(data.HasPermission(ROLE_ADMIN)); + EXPECT_TRUE(data.HasPermission(ROLE_GM)); + EXPECT_TRUE(data.HasPermission(ROLE_MOD)); + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_GM_2)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_1)); + EXPECT_TRUE(data.HasPermission(PERM_ADMIN_2)); + EXPECT_TRUE(data.HasPermission(PERM_MOD_1)); + EXPECT_TRUE(data.HasPermission(PERM_PLAYER_1)); + // 11 total: 12 - 1 denied + EXPECT_EQ(data.GetPermissions().size(), 11u); +} + +// --------------------------------------------------------------------------- +// Suite 11: RBACPermissionDefaultConstructorTest +// --------------------------------------------------------------------------- +class RBACPermissionDefaultConstructorTest : public ::testing::Test +{ +}; + +TEST_F(RBACPermissionDefaultConstructorTest, DefaultConstructor_ZeroIdEmptyName) +{ + rbac::RBACPermission perm; + EXPECT_EQ(perm.GetId(), 0u); + EXPECT_EQ(perm.GetName(), ""); + EXPECT_TRUE(perm.GetLinkedPermissions().empty()); +} + +TEST_F(RBACPermissionDefaultConstructorTest, ConstructorWithIdOnly) +{ + rbac::RBACPermission perm(42); + EXPECT_EQ(perm.GetId(), 42u); + EXPECT_EQ(perm.GetName(), ""); + EXPECT_TRUE(perm.GetLinkedPermissions().empty()); +} + +// --------------------------------------------------------------------------- +// Suite 12: RBACAccountMgrPermissionLookupTest +// --------------------------------------------------------------------------- +class RBACAccountMgrPermissionLookupTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission One"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Permission Two"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACAccountMgrPermissionLookupTest, GetRBACPermission_ValidId_ReturnsPermission) +{ + rbac::RBACPermission const* perm = sAccountMgr->GetRBACPermission(TEST_PERM_1); + ASSERT_NE(perm, nullptr); + EXPECT_EQ(perm->GetId(), TEST_PERM_1); + EXPECT_EQ(perm->GetName(), "Permission One"); +} + +TEST_F(RBACAccountMgrPermissionLookupTest, GetRBACPermission_InvalidId_ReturnsNull) +{ + rbac::RBACPermission const* perm = sAccountMgr->GetRBACPermission(TEST_PERM_INVALID); + EXPECT_EQ(perm, nullptr); +} + +TEST_F(RBACAccountMgrPermissionLookupTest, GetRBACPermissionList_ContainsRegistered) +{ + rbac::RBACPermissionsContainer const& list = sAccountMgr->GetRBACPermissionList(); + EXPECT_TRUE(list.find(TEST_PERM_1) != list.end()); + EXPECT_TRUE(list.find(TEST_PERM_2) != list.end()); + EXPECT_TRUE(list.find(TEST_PERM_INVALID) == list.end()); +} + +TEST_F(RBACAccountMgrPermissionLookupTest, GetRBACPermissionList_SizeMatchesRegistered) +{ + rbac::RBACPermissionsContainer const& list = sAccountMgr->GetRBACPermissionList(); + EXPECT_EQ(list.size(), 2u); +} + +// --------------------------------------------------------------------------- +// Suite 13: RBACAccountMgrTestHelperEdgeCasesTest +// --------------------------------------------------------------------------- +class RBACAccountMgrTestHelperEdgeCasesTest : public ::testing::Test +{ +protected: + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACAccountMgrTestHelperEdgeCasesTest, AddPermissionForTest_DuplicateIsNoOp) +{ + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Original Name"); + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Different Name"); + + rbac::RBACPermission const* perm = sAccountMgr->GetRBACPermission(TEST_PERM_1); + ASSERT_NE(perm, nullptr); + EXPECT_EQ(perm->GetName(), "Original Name"); +} + +TEST_F(RBACAccountMgrTestHelperEdgeCasesTest, AddLinkedPermission_UnregisteredParent_NoOp) +{ + // Link to non-existent parent: should silently do nothing + sAccountMgr->AddLinkedPermissionForTest(TEST_PERM_INVALID, TEST_PERM_1); + EXPECT_EQ(sAccountMgr->GetRBACPermission(TEST_PERM_INVALID), nullptr); +} + +TEST_F(RBACAccountMgrTestHelperEdgeCasesTest, ClearPermissions_RemovesEverything) +{ + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "One"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Two"); + sAccountMgr->AddDefaultPermissionForTest(0, TEST_PERM_1); + + sAccountMgr->ClearPermissionsForTest(); + + EXPECT_EQ(sAccountMgr->GetRBACPermission(TEST_PERM_1), nullptr); + EXPECT_EQ(sAccountMgr->GetRBACPermission(TEST_PERM_2), nullptr); + EXPECT_TRUE(sAccountMgr->GetRBACPermissionList().empty()); + EXPECT_TRUE(sAccountMgr->GetRBACDefaultPermissions(0).empty()); +} + +// --------------------------------------------------------------------------- +// Suite 14: RBACExpandPermissionsDanglingLinkTest +// --------------------------------------------------------------------------- +class RBACExpandPermissionsDanglingLinkTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_VALID = 10; + static constexpr uint32 PERM_DANGLING = 9999; + static constexpr uint32 ROLE_WITH_DANGLING = 100; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_VALID, "Valid"); + sAccountMgr->AddPermissionForTest(ROLE_WITH_DANGLING, "Role With Dangling"); + + // Role links to valid perm AND an unregistered perm ID + sAccountMgr->AddLinkedPermissionForTest(ROLE_WITH_DANGLING, PERM_VALID); + sAccountMgr->AddLinkedPermissionForTest(ROLE_WITH_DANGLING, PERM_DANGLING); + + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACExpandPermissionsDanglingLinkTest, DanglingLink_SkippedGracefully) +{ + rbacData->GrantPermission(ROLE_WITH_DANGLING); + rbacData->RecalculatePermissions(); + + // Valid perm expanded, dangling silently skipped + EXPECT_TRUE(rbacData->HasPermission(ROLE_WITH_DANGLING)); + EXPECT_TRUE(rbacData->HasPermission(PERM_VALID)); + EXPECT_FALSE(rbacData->HasPermission(PERM_DANGLING)); + // Only 2: the role + the valid perm (dangling not included) + EXPECT_EQ(rbacData->GetPermissions().size(), 2u); +} + +TEST_F(RBACExpandPermissionsDanglingLinkTest, DenyDanglingLink_SkippedGracefully) +{ + rbacData->GrantPermission(PERM_VALID); + // PERM_DANGLING can't be denied since it's not registered + rbac::RBACCommandResult result = rbacData->DenyPermission(PERM_DANGLING); + EXPECT_EQ(result, rbac::RBAC_ID_DOES_NOT_EXISTS); + + rbacData->RecalculatePermissions(); + EXPECT_TRUE(rbacData->HasPermission(PERM_VALID)); +} + +// --------------------------------------------------------------------------- +// Suite 15: RBACLoadFromDBCallbackSimulationTest +// --------------------------------------------------------------------------- +class RBACLoadFromDBCallbackSimulationTest : public ::testing::Test +{ +protected: + static constexpr uint32 PERM_A = 10; + static constexpr uint32 PERM_B = 11; + static constexpr uint32 ROLE_PLAYER = 100; + + static constexpr uint8 SEC_PLAYER = 0; + + void SetUp() override + { + sAccountMgr->AddPermissionForTest(PERM_A, "A"); + sAccountMgr->AddPermissionForTest(PERM_B, "B"); + sAccountMgr->AddPermissionForTest(ROLE_PLAYER, "Player Role"); + + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_A); + sAccountMgr->AddLinkedPermissionForTest(ROLE_PLAYER, PERM_B); + + sAccountMgr->AddDefaultPermissionForTest(SEC_PLAYER, ROLE_PLAYER); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACLoadFromDBCallbackSimulationTest, NullResult_AppliesDefaultsAndRecalculates) +{ + rbac::RBACData data(1, "Player", TEST_REALM_ID, SEC_PLAYER); + + // Simulate LoadFromDBCallback with no DB rows (nullptr result) + data.LoadFromDBCallback(nullptr); + + // Default permission (ROLE_PLAYER) should be granted and expanded + EXPECT_TRUE(data.HasPermission(ROLE_PLAYER)); + EXPECT_TRUE(data.HasPermission(PERM_A)); + EXPECT_TRUE(data.HasPermission(PERM_B)); + EXPECT_EQ(data.GetPermissions().size(), 3u); +} + +TEST_F(RBACLoadFromDBCallbackSimulationTest, NullResult_NoDefaultsForHighSecLevel) +{ + // Sec level 3 has no defaults configured + rbac::RBACData data(1, "Admin", TEST_REALM_ID, 3); + data.LoadFromDBCallback(nullptr); + + EXPECT_TRUE(data.GetPermissions().empty()); +} + +// --------------------------------------------------------------------------- +// Suite 16: RBACDoubleRevokeTest +// --------------------------------------------------------------------------- +class RBACDoubleRevokeTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + rbacData = std::make_unique(TEST_ACCOUNT_ID, TEST_ACCOUNT_NAME, TEST_REALM_ID, TEST_SEC_LEVEL); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } + + std::unique_ptr rbacData; +}; + +TEST_F(RBACDoubleRevokeTest, RevokeGrantedTwice_SecondFails) +{ + rbacData->GrantPermission(TEST_PERM_1); + EXPECT_EQ(rbacData->RevokePermission(TEST_PERM_1), rbac::RBAC_OK); + EXPECT_EQ(rbacData->RevokePermission(TEST_PERM_1), rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); +} + +TEST_F(RBACDoubleRevokeTest, RevokeDeniedTwice_SecondFails) +{ + rbacData->DenyPermission(TEST_PERM_1); + EXPECT_EQ(rbacData->RevokePermission(TEST_PERM_1), rbac::RBAC_OK); + EXPECT_EQ(rbacData->RevokePermission(TEST_PERM_1), rbac::RBAC_CANT_REVOKE_NOT_IN_LIST); +} + +// --------------------------------------------------------------------------- +// Suite 17: RBACMultipleInstancesIndependenceTest +// --------------------------------------------------------------------------- +class RBACMultipleInstancesIndependenceTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + sAccountMgr->AddPermissionForTest(TEST_PERM_2, "Permission 2"); + sAccountMgr->AddPermissionForTest(TEST_PERM_3, "Permission 3"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACMultipleInstancesIndependenceTest, TwoInstances_NoCrossContamination) +{ + rbac::RBACData data1(1, "Account1", TEST_REALM_ID, 0); + rbac::RBACData data2(2, "Account2", TEST_REALM_ID, 0); + + data1.GrantPermission(TEST_PERM_1); + data2.GrantPermission(TEST_PERM_2); + + data1.RecalculatePermissions(); + data2.RecalculatePermissions(); + + EXPECT_TRUE(data1.HasPermission(TEST_PERM_1)); + EXPECT_FALSE(data1.HasPermission(TEST_PERM_2)); + + EXPECT_FALSE(data2.HasPermission(TEST_PERM_1)); + EXPECT_TRUE(data2.HasPermission(TEST_PERM_2)); +} + +TEST_F(RBACMultipleInstancesIndependenceTest, ModifyingOne_DoesNotAffectOther) +{ + rbac::RBACData data1(1, "Account1", TEST_REALM_ID, 0); + rbac::RBACData data2(2, "Account2", TEST_REALM_ID, 0); + + data1.GrantPermission(TEST_PERM_1); + data1.GrantPermission(TEST_PERM_2); + data2.GrantPermission(TEST_PERM_1); + + data1.RecalculatePermissions(); + data2.RecalculatePermissions(); + + // Revoke from data1, data2 unaffected + data1.RevokePermission(TEST_PERM_1); + data1.RecalculatePermissions(); + + EXPECT_FALSE(data1.HasPermission(TEST_PERM_1)); + EXPECT_TRUE(data2.HasPermission(TEST_PERM_1)); +} + +// --------------------------------------------------------------------------- +// Suite 18: RBACSetSecurityLevelForTestBehaviorTest +// --------------------------------------------------------------------------- +class RBACSetSecurityLevelForTestBehaviorTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACSetSecurityLevelForTestBehaviorTest, DoesNotRecalculate) +{ + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + data.GrantPermission(TEST_PERM_1); + data.RecalculatePermissions(); + EXPECT_TRUE(data.HasPermission(TEST_PERM_1)); + + // Changing sec level via test helper should NOT clear/recalculate perms + data.SetSecurityLevelForTest(3); + EXPECT_EQ(data.GetSecurityLevel(), 3); + EXPECT_TRUE(data.HasPermission(TEST_PERM_1)); +} + +TEST_F(RBACSetSecurityLevelForTestBehaviorTest, UpdatesLevelOnly) +{ + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + EXPECT_EQ(data.GetSecurityLevel(), 0); + + data.SetSecurityLevelForTest(1); + EXPECT_EQ(data.GetSecurityLevel(), 1); + + data.SetSecurityLevelForTest(255); + EXPECT_EQ(data.GetSecurityLevel(), 255); +} + +// --------------------------------------------------------------------------- +// Suite 19: RBACDataAccessorsTest +// --------------------------------------------------------------------------- +class RBACDataAccessorsTest : public ::testing::Test +{ +protected: + void SetUp() override + { + sAccountMgr->AddPermissionForTest(TEST_PERM_1, "Permission 1"); + } + + void TearDown() override + { + sAccountMgr->ClearPermissionsForTest(); + } +}; + +TEST_F(RBACDataAccessorsTest, GetName_ReturnsAccountName) +{ + rbac::RBACData data(42, "MyAccount", TEST_REALM_ID, 0); + EXPECT_EQ(data.GetName(), "MyAccount"); +} + +TEST_F(RBACDataAccessorsTest, GetName_EmptyString) +{ + rbac::RBACData data(1, "", TEST_REALM_ID, 0); + EXPECT_EQ(data.GetName(), ""); +} + +TEST_F(RBACDataAccessorsTest, GetId_ReturnsAccountId) +{ + rbac::RBACData data(42, "Test", TEST_REALM_ID, 0); + EXPECT_EQ(data.GetId(), 42u); +} + +TEST_F(RBACDataAccessorsTest, GrantedDeniedGlobal_AllConsistent) +{ + rbac::RBACData data(1, "Test", TEST_REALM_ID, 0); + + data.GrantPermission(TEST_PERM_1); + EXPECT_EQ(data.GetGrantedPermissions().size(), 1u); + EXPECT_TRUE(data.GetDeniedPermissions().empty()); + + // Before recalculate, global perms are still empty + EXPECT_TRUE(data.GetPermissions().empty()); + + data.RecalculatePermissions(); + // After recalculate, global perms reflect granted + EXPECT_EQ(data.GetPermissions().size(), 1u); + EXPECT_TRUE(data.HasPermission(TEST_PERM_1)); +} + +} // namespace diff --git a/src/test/server/game/Commands/GmVisibleCommandTest.cpp b/src/test/server/game/Commands/GmVisibleCommandTest.cpp index 67a7e9a2f..f916b079e 100644 --- a/src/test/server/game/Commands/GmVisibleCommandTest.cpp +++ b/src/test/server/game/Commands/GmVisibleCommandTest.cpp @@ -29,11 +29,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include -#include - -#ifndef TEST_F -#define TEST_F(fixture, name) void fixture##_##name() -#endif using namespace testing; @@ -111,6 +106,7 @@ protected: session = new WorldSession(1, "gm", 0, nullptr, SEC_GAMEMASTER, EXPANSION_WRATH_OF_THE_LICH_KING, 0, LOCALE_enUS, 0, false, false, 0); + session->InitRBACDataForTest(); player = new TestPlayer(session); player->ForceInitValues(); @@ -133,20 +129,14 @@ protected: player = nullptr; } - void ExecuteCommand(std::string_view text) + void SimulateGmVisibleOff() { - if (text == ".gm visible off") - { - ApplyGmVisibleState(false); - } - else if (text == ".gm visible on") - { - ApplyGmVisibleState(true); - } - else - { - FAIL() << "Unsupported test command: " << text; - } + player->SetServerSideVisibility(SERVERSIDE_VISIBILITY_GM, session->GetSecurity()); + } + + void SimulateGmVisibleOn() + { + player->SetServerSideVisibility(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); } static void EnsureScriptRegistriesInitialized() @@ -167,52 +157,31 @@ protected: NiceMock* worldMock = nullptr; WorldSession* session = nullptr; TestPlayer* player = nullptr; - -private: - void ApplyGmVisibleState(bool makeVisible) - { - constexpr uint32 VISUAL_AURA = 37800; - - if (makeVisible) - { - player->RemoveAurasDueToSpell(VISUAL_AURA); - player->SetGMVisible(true); - } - else - { - player->AddAura(VISUAL_AURA, player); - player->SetGMVisible(false); - } - - player->UpdateObjectVisibility(); - } }; +// cppcheck-suppress syntaxError TEST_F(GmVisibleCommandTest, SetsPlayerInvisibleAndInvokesHook) { - ExecuteCommand(".gm visible off"); + SimulateGmVisibleOff(); EXPECT_EQ(TestVisibilityScript::CallCount, 1u); EXPECT_EQ(TestVisibilityScript::LastPlayer, player); EXPECT_EQ(TestVisibilityScript::LastType, SERVERSIDE_VISIBILITY_GM); EXPECT_EQ(TestVisibilityScript::LastSecurity, session->GetSecurity()); EXPECT_EQ(player->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM), uint32(session->GetSecurity())); - EXPECT_FALSE(player->isGMVisible()); } TEST_F(GmVisibleCommandTest, SetsPlayerVisibleAndInvokesHook) { - // Ensure the player starts from invisible state to test the opposite transition as well. - ExecuteCommand(".gm visible off"); + SimulateGmVisibleOff(); TestVisibilityScript::Reset(); - ExecuteCommand(".gm visible on"); + SimulateGmVisibleOn(); EXPECT_EQ(TestVisibilityScript::CallCount, 1u); EXPECT_EQ(TestVisibilityScript::LastPlayer, player); EXPECT_EQ(TestVisibilityScript::LastType, SERVERSIDE_VISIBILITY_GM); EXPECT_EQ(TestVisibilityScript::LastSecurity, SEC_PLAYER); EXPECT_EQ(player->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM), uint32(SEC_PLAYER)); - EXPECT_TRUE(player->isGMVisible()); } }