diff options
author | Giacomo Pozzoni <giacomopoz@gmail.com> | 2021-07-17 11:22:11 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-03-11 18:35:58 +0100 |
commit | c9e685bd9a0ac524edb8fe64eb6ec37540c55acc (patch) | |
tree | 9ab53726d94f015b9f8baa450aff741eb199d955 /src | |
parent | 1b0435b6eafb0ee62e925bf2692db7eab963342a (diff) |
Core/SAI: Warn when an unused parameter is set in the database (#26628)
* Core/SAI: Warn when an unused parameter is set in the database
* Warn when an unused parameter is set in the database as all unused parameters are supposed to be set to 0.
* Remove unused struct from union.
* Add a new struct simpleTalk for SMART_ACTION_SIMPLE_TALK instead of reusing only some fields of struct talk from SMART_ACTION_TALK
* Add addAura and flag structs to be used instead of generic ones to match the parameters used by actions
* Add randRangeTimedActionList struct to be used instead of generic ones to match the parameters used by actions.
* Remove unused action structs.
(cherry picked from commit aa7279df095d086f7223a1fa13d11a0e58f1cf10)
Diffstat (limited to 'src')
4 files changed, 449 insertions, 83 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 301dcb88acf..bc91ee9c5ad 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -328,14 +328,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (WorldObject* target : targets) { if (IsCreature(target)) - sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.talk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : nullptr); + sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : nullptr); else if (IsPlayer(target) && me) { Unit* templastInvoker = GetLastInvoker(); - sCreatureTextMgr->SendChat(me, uint8(e.action.talk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, SoundKitPlayType::Normal, TEAM_OTHER, false, target->ToPlayer()); + sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, SoundKitPlayType::Normal, TEAM_OTHER, false, target->ToPlayer()); } TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: %s %s, textGroupId: %u", - target->GetName().c_str(), target->GetGUID().ToString().c_str(), uint8(e.action.talk.textGroupID)); + target->GetName().c_str(), target->GetGUID().ToString().c_str(), uint8(e.action.simpleTalk.textGroupID)); } break; } @@ -704,9 +704,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { if (IsUnit(target)) { - target->ToUnit()->AddAura(e.action.cast.spell, target->ToUnit()); + target->ToUnit()->AddAura(e.action.addAura.spell, target->ToUnit()); TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura %u to unit %s", - e.action.cast.spell, target->GetGUID().ToString().c_str()); + e.action.addAura.spell, target->GetGUID().ToString().c_str()); } } break; @@ -1757,21 +1757,21 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { for (WorldObject* target : targets) if (IsCreature(target)) - target->ToUnit()->SetNpcFlags(NPCFlags(e.action.unitFlag.flag)); + target->ToUnit()->SetNpcFlags(NPCFlags(e.action.flag.flag)); break; } case SMART_ACTION_ADD_NPC_FLAG: { for (WorldObject* target : targets) if (IsCreature(target)) - target->ToUnit()->AddNpcFlag(NPCFlags(e.action.unitFlag.flag)); + target->ToUnit()->AddNpcFlag(NPCFlags(e.action.flag.flag)); break; } case SMART_ACTION_REMOVE_NPC_FLAG: { for (WorldObject* target : targets) if (IsCreature(target)) - target->ToUnit()->RemoveNpcFlag(NPCFlags(e.action.unitFlag.flag)); + target->ToUnit()->RemoveNpcFlag(NPCFlags(e.action.flag.flag)); break; } case SMART_ACTION_CROSS_CAST: @@ -1845,7 +1845,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: { - uint32 id = urand(e.action.randTimedActionList.actionLists[0], e.action.randTimedActionList.actionLists[1]); + uint32 id = urand(e.action.randRangeTimedActionList.idMin, e.action.randRangeTimedActionList.idMax); if (e.GetTargetType() == SMART_TARGET_NONE) { TC_LOG_ERROR("sql.sql", "SmartScript: Entry " SI64FMTD " SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); @@ -1966,21 +1966,21 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_DYNAMIC_FLAG: { for (WorldObject* target : targets) - target->SetDynamicFlags(e.action.unitFlag.flag); + target->SetDynamicFlags(e.action.flag.flag); break; } case SMART_ACTION_ADD_DYNAMIC_FLAG: { for (WorldObject* target : targets) - target->AddDynamicFlag(e.action.unitFlag.flag); + target->AddDynamicFlag(e.action.flag.flag); break; } case SMART_ACTION_REMOVE_DYNAMIC_FLAG: { for (WorldObject* target : targets) - target->RemoveDynamicFlag(e.action.unitFlag.flag); + target->RemoveDynamicFlag(e.action.flag.flag); break; } @@ -2374,7 +2374,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; for (WorldObject* const target : targets) if (IsUnit(target)) - me->GetThreatManager().AddThreat(target->ToUnit(), float(e.action.threatPCT.threatINC) - float(e.action.threatPCT.threatDEC), nullptr, true, true); + me->GetThreatManager().AddThreat(target->ToUnit(), float(e.action.threat.threatINC) - float(e.action.threat.threatDEC), nullptr, true, true); break; } case SMART_ACTION_LOAD_EQUIPMENT: @@ -3020,7 +3020,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, break; } - if (Creature* target = ref->FindNearestCreature(e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100), !e.target.closest.dead)) + if (Creature* target = ref->FindNearestCreature(e.target.unitClosest.entry, float(e.target.unitClosest.dist ? e.target.unitClosest.dist : 100), !e.target.unitClosest.dead)) targets.push_back(target); break; } @@ -3037,7 +3037,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, break; } - if (GameObject* target = ref->FindNearestGameObject(e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100))) + if (GameObject* target = ref->FindNearestGameObject(e.target.goClosest.entry, float(e.target.goClosest.dist ? e.target.goClosest.dist : 100))) targets.push_back(target); break; } @@ -3096,7 +3096,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, { if (me && me->CanHaveThreatList()) for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) - if (!e.target.hostilRandom.maxDist || me->IsWithinCombatRange(ref->GetVictim(), float(e.target.hostilRandom.maxDist))) + if (!e.target.threatList.maxDist || me->IsWithinCombatRange(ref->GetVictim(), float(e.target.threatList.maxDist))) targets.push_back(ref->GetVictim()); break; } @@ -3144,7 +3144,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, } case SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT: { - if (GameObject* target = baseObject->FindNearestUnspawnedGameObject(e.target.closest.entry, float(e.target.closest.dist ? e.target.closest.dist : 100))) + if (GameObject* target = baseObject->FindNearestUnspawnedGameObject(e.target.goClosest.entry, float(e.target.goClosest.dist ? e.target.goClosest.dist : 100))) targets.push_back(target); break; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 6f48fa33528..649deac0178 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -603,9 +603,8 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e) TC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.playerOnly); TC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.isInLos); break; - case SMART_TARGET_CLOSEST_GAMEOBJECT: case SMART_TARGET_CLOSEST_CREATURE: - TC_SAI_IS_BOOLEAN_VALID(e, e.target.closest.dead); + TC_SAI_IS_BOOLEAN_VALID(e, e.target.unitClosest.dead); break; case SMART_TARGET_CLOSEST_ENEMY: TC_SAI_IS_BOOLEAN_VALID(e, e.target.closestAttackable.playerOnly); @@ -616,6 +615,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e) case SMART_TARGET_OWNER_OR_SUMMONER: TC_SAI_IS_BOOLEAN_VALID(e, e.target.owner.useCharmerOrOwner); break; + case SMART_TARGET_CLOSEST_GAMEOBJECT: case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_SELF: case SMART_TARGET_VICTIM: @@ -631,6 +631,10 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e) TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled target_type(%u), Entry " SI64FMTD " SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } + + if (!CheckUnusedTargetParams(e)) + return false; + return true; } @@ -764,6 +768,366 @@ bool SmartAIMgr::IsSpellVisualKitValid(SmartScriptHolder const& e, uint32 entry) return true; } +bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) +{ + size_t paramsStructSize = [&]() -> size_t + { + constexpr size_t NO_PARAMS = size_t(0); + switch (e.event.type) + { + case SMART_EVENT_UPDATE_IC: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_UPDATE_OOC: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_HEALTH_PCT: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_MANA_PCT: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_AGGRO: return NO_PARAMS; + case SMART_EVENT_KILL: return sizeof(SmartEvent::kill); + case SMART_EVENT_DEATH: return NO_PARAMS; + case SMART_EVENT_EVADE: return NO_PARAMS; + case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit); + case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los); + case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn); + case SMART_EVENT_TARGET_HEALTH_PCT: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_VICTIM_CASTING: return sizeof(SmartEvent::targetCasting); + case SMART_EVENT_FRIENDLY_HEALTH: return sizeof(SmartEvent::friendlyHealth); + case SMART_EVENT_FRIENDLY_IS_CC: return sizeof(SmartEvent::friendlyCC); + case SMART_EVENT_FRIENDLY_MISSING_BUFF: return sizeof(SmartEvent::missingBuff); + case SMART_EVENT_SUMMONED_UNIT: return sizeof(SmartEvent::summoned); + case SMART_EVENT_TARGET_MANA_PCT: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_ACCEPTED_QUEST: return sizeof(SmartEvent::quest); + case SMART_EVENT_REWARD_QUEST: return sizeof(SmartEvent::quest); + case SMART_EVENT_REACHED_HOME: return NO_PARAMS; + case SMART_EVENT_RECEIVE_EMOTE: return sizeof(SmartEvent::emote); + case SMART_EVENT_HAS_AURA: return sizeof(SmartEvent::aura); + case SMART_EVENT_TARGET_BUFFED: return sizeof(SmartEvent::aura); + case SMART_EVENT_RESET: return NO_PARAMS; + case SMART_EVENT_IC_LOS: return sizeof(SmartEvent::los); + case SMART_EVENT_PASSENGER_BOARDED: return sizeof(SmartEvent::minMax); + case SMART_EVENT_PASSENGER_REMOVED: return sizeof(SmartEvent::minMax); + case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm); + case SMART_EVENT_CHARMED_TARGET: return NO_PARAMS; + case SMART_EVENT_SPELLHIT_TARGET: return sizeof(SmartEvent::spellHit); + case SMART_EVENT_DAMAGED: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_DAMAGED_TARGET: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_MOVEMENTINFORM: return sizeof(SmartEvent::movementInform); + case SMART_EVENT_SUMMON_DESPAWNED: return sizeof(SmartEvent::summoned); + case SMART_EVENT_CORPSE_REMOVED: return NO_PARAMS; + case SMART_EVENT_AI_INIT: return NO_PARAMS; + case SMART_EVENT_DATA_SET: return sizeof(SmartEvent::dataSet); + case SMART_EVENT_WAYPOINT_START: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_WAYPOINT_REACHED: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_TRANSPORT_ADDPLAYER: return NO_PARAMS; + case SMART_EVENT_TRANSPORT_ADDCREATURE: return sizeof(SmartEvent::transportAddCreature); + case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: return NO_PARAMS; + case SMART_EVENT_TRANSPORT_RELOCATE: return sizeof(SmartEvent::transportRelocate); + case SMART_EVENT_INSTANCE_PLAYER_ENTER: return sizeof(SmartEvent::instancePlayerEnter); + case SMART_EVENT_AREATRIGGER_ONTRIGGER: return sizeof(SmartEvent::areatrigger); + case SMART_EVENT_QUEST_ACCEPTED: return NO_PARAMS; + case SMART_EVENT_QUEST_OBJ_COMPLETION: return NO_PARAMS; + case SMART_EVENT_QUEST_COMPLETION: return NO_PARAMS; + case SMART_EVENT_QUEST_REWARDED: return NO_PARAMS; + case SMART_EVENT_QUEST_FAIL: return NO_PARAMS; + case SMART_EVENT_TEXT_OVER: return sizeof(SmartEvent::textOver); + case SMART_EVENT_RECEIVE_HEAL: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_JUST_SUMMONED: return NO_PARAMS; + case SMART_EVENT_WAYPOINT_PAUSED: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_WAYPOINT_RESUMED: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_WAYPOINT_STOPPED: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_WAYPOINT_ENDED: return sizeof(SmartEvent::waypoint); + case SMART_EVENT_TIMED_EVENT_TRIGGERED: return sizeof(SmartEvent::timedEvent); + case SMART_EVENT_UPDATE: return sizeof(SmartEvent::minMaxRepeat); + case SMART_EVENT_LINK: return NO_PARAMS; + case SMART_EVENT_GOSSIP_SELECT: return sizeof(SmartEvent::gossip); + case SMART_EVENT_JUST_CREATED: return NO_PARAMS; + case SMART_EVENT_GOSSIP_HELLO: return sizeof(SmartEvent::gossipHello); + case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS; + case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange); + case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget); + case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent); + case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent); + case SMART_EVENT_GO_LOOT_STATE_CHANGED: return sizeof(SmartEvent::goLootStateChanged); + case SMART_EVENT_GO_EVENT_INFORM: return sizeof(SmartEvent::eventInform); + case SMART_EVENT_ACTION_DONE: return sizeof(SmartEvent::doAction); + case SMART_EVENT_ON_SPELLCLICK: return NO_PARAMS; + case SMART_EVENT_FRIENDLY_HEALTH_PCT: return sizeof(SmartEvent::friendlyHealthPct); + case SMART_EVENT_DISTANCE_CREATURE: return sizeof(SmartEvent::distance); + case SMART_EVENT_DISTANCE_GAMEOBJECT: return sizeof(SmartEvent::distance); + case SMART_EVENT_COUNTER_SET: return sizeof(SmartEvent::counter); + case SMART_EVENT_SCENE_START: return NO_PARAMS; + case SMART_EVENT_SCENE_TRIGGER: return NO_PARAMS; + case SMART_EVENT_SCENE_CANCEL: return NO_PARAMS; + case SMART_EVENT_SCENE_COMPLETE: return NO_PARAMS; + case SMART_EVENT_SUMMONED_UNIT_DIES: return sizeof(SmartEvent::summoned); + default: + TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return sizeof(SmartEvent::raw); + } + }(); + + static size_t rawCount = sizeof(SmartEvent::raw) / sizeof(uint32); + size_t paramsCount = paramsStructSize / sizeof(uint32); + + bool valid = true; + for (size_t index = paramsCount; index < rawCount; index++) + { + uint32 value = ((uint32*)&e.event.raw)[index]; + if (value != 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has unused event_param%zu with value %u, it must be 0, skipped.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value); + valid = false; + } + } + + return valid; +} + +bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) +{ + size_t paramsStructSize = [&]() -> size_t + { + constexpr size_t NO_PARAMS = size_t(0); + switch (e.action.type) + { + case SMART_ACTION_NONE: return NO_PARAMS; + case SMART_ACTION_TALK: return sizeof(SmartAction::talk); + case SMART_ACTION_SET_FACTION: return sizeof(SmartAction::faction); + case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: return sizeof(SmartAction::morphOrMount); + case SMART_ACTION_SOUND: return sizeof(SmartAction::sound); + case SMART_ACTION_PLAY_EMOTE: return sizeof(SmartAction::emote); + case SMART_ACTION_FAIL_QUEST: return sizeof(SmartAction::quest); + case SMART_ACTION_OFFER_QUEST: return sizeof(SmartAction::questOffer); + case SMART_ACTION_SET_REACT_STATE: return sizeof(SmartAction::react); + case SMART_ACTION_ACTIVATE_GOBJECT: return NO_PARAMS; + case SMART_ACTION_RANDOM_EMOTE: return sizeof(SmartAction::randomEmote); + case SMART_ACTION_CAST: return sizeof(SmartAction::cast); + case SMART_ACTION_SUMMON_CREATURE: return sizeof(SmartAction::summonCreature); + case SMART_ACTION_THREAT_SINGLE_PCT: return sizeof(SmartAction::threatPCT); + case SMART_ACTION_THREAT_ALL_PCT: return sizeof(SmartAction::threatPCT); + case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: return sizeof(SmartAction::quest); + case SMART_ACTION_SET_INGAME_PHASE_GROUP: return sizeof(SmartAction::ingamePhaseGroup); + case SMART_ACTION_SET_EMOTE_STATE: return sizeof(SmartAction::emote); + case SMART_ACTION_SET_UNIT_FLAG: return sizeof(SmartAction::unitFlag); + case SMART_ACTION_REMOVE_UNIT_FLAG: return sizeof(SmartAction::unitFlag); + case SMART_ACTION_AUTO_ATTACK: return sizeof(SmartAction::autoAttack); + case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: return sizeof(SmartAction::combatMove); + case SMART_ACTION_SET_EVENT_PHASE: return sizeof(SmartAction::setEventPhase); + case SMART_ACTION_INC_EVENT_PHASE: return sizeof(SmartAction::incEventPhase); + case SMART_ACTION_EVADE: return sizeof(SmartAction::evade); + case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::fleeAssist); + case SMART_ACTION_CALL_GROUPEVENTHAPPENS: return sizeof(SmartAction::quest); + case SMART_ACTION_COMBAT_STOP: return NO_PARAMS; + case SMART_ACTION_REMOVEAURASFROMSPELL: return sizeof(SmartAction::removeAura); + case SMART_ACTION_FOLLOW: return sizeof(SmartAction::follow); + case SMART_ACTION_RANDOM_PHASE: return sizeof(SmartAction::randomPhase); + case SMART_ACTION_RANDOM_PHASE_RANGE: return sizeof(SmartAction::randomPhaseRange); + case SMART_ACTION_RESET_GOBJECT: return NO_PARAMS; + case SMART_ACTION_CALL_KILLEDMONSTER: return sizeof(SmartAction::killedMonster); + case SMART_ACTION_SET_INST_DATA: return sizeof(SmartAction::setInstanceData); + case SMART_ACTION_SET_INST_DATA64: return sizeof(SmartAction::setInstanceData64); + case SMART_ACTION_UPDATE_TEMPLATE: return sizeof(SmartAction::updateTemplate); + case SMART_ACTION_DIE: return NO_PARAMS; + case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: return NO_PARAMS; + case SMART_ACTION_CALL_FOR_HELP: return sizeof(SmartAction::callHelp); + case SMART_ACTION_SET_SHEATH: return sizeof(SmartAction::setSheath); + case SMART_ACTION_FORCE_DESPAWN: return sizeof(SmartAction::forceDespawn); + case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL: return sizeof(SmartAction::invincHP); + case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: return sizeof(SmartAction::morphOrMount); + case SMART_ACTION_SET_INGAME_PHASE_ID: return sizeof(SmartAction::ingamePhaseId); + case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData); + case SMART_ACTION_ATTACK_STOP: return NO_PARAMS; + case SMART_ACTION_SET_VISIBILITY: return sizeof(SmartAction::visibility); + case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::active); + case SMART_ACTION_ATTACK_START: return NO_PARAMS; + case SMART_ACTION_SUMMON_GO: return sizeof(SmartAction::summonGO); + case SMART_ACTION_KILL_UNIT: return NO_PARAMS; + case SMART_ACTION_ACTIVATE_TAXI: return sizeof(SmartAction::taxi); + case SMART_ACTION_WP_START: return sizeof(SmartAction::wpStart); + case SMART_ACTION_WP_PAUSE: return sizeof(SmartAction::wpPause); + case SMART_ACTION_WP_STOP: return sizeof(SmartAction::wpStop); + case SMART_ACTION_ADD_ITEM: return sizeof(SmartAction::item); + case SMART_ACTION_REMOVE_ITEM: return sizeof(SmartAction::item); + case SMART_ACTION_INSTALL_AI_TEMPLATE: return sizeof(SmartAction::installTtemplate); + case SMART_ACTION_SET_RUN: return sizeof(SmartAction::setRun); + case SMART_ACTION_SET_DISABLE_GRAVITY: return sizeof(SmartAction::setDisableGravity); + case SMART_ACTION_SET_SWIM: return sizeof(SmartAction::setSwim); + case SMART_ACTION_TELEPORT: return sizeof(SmartAction::teleport); + case SMART_ACTION_SET_COUNTER: return sizeof(SmartAction::setCounter); + case SMART_ACTION_STORE_TARGET_LIST: return sizeof(SmartAction::storeTargets); + case SMART_ACTION_WP_RESUME: return NO_PARAMS; + case SMART_ACTION_SET_ORIENTATION: return NO_PARAMS; + case SMART_ACTION_CREATE_TIMED_EVENT: return sizeof(SmartAction::timeEvent); + case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie); + case SMART_ACTION_MOVE_TO_POS: return sizeof(SmartAction::moveToPos); + case SMART_ACTION_ENABLE_TEMP_GOBJ: return sizeof(SmartAction::enableTempGO); + case SMART_ACTION_EQUIP: return sizeof(SmartAction::equip); + case SMART_ACTION_CLOSE_GOSSIP: return NO_PARAMS; + case SMART_ACTION_TRIGGER_TIMED_EVENT: return sizeof(SmartAction::timeEvent); + case SMART_ACTION_REMOVE_TIMED_EVENT: return sizeof(SmartAction::timeEvent); + case SMART_ACTION_ADD_AURA: return sizeof(SmartAction::addAura); + case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT: return NO_PARAMS; + case SMART_ACTION_RESET_SCRIPT_BASE_OBJECT: return NO_PARAMS; + case SMART_ACTION_CALL_SCRIPT_RESET: return NO_PARAMS; + case SMART_ACTION_SET_RANGED_MOVEMENT: return sizeof(SmartAction::setRangedMovement); + case SMART_ACTION_CALL_TIMED_ACTIONLIST: return sizeof(SmartAction::timedActionList); + case SMART_ACTION_SET_NPC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_REMOVE_NPC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_SIMPLE_TALK: return sizeof(SmartAction::simpleTalk); + case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast); + case SMART_ACTION_CROSS_CAST: return sizeof(SmartAction::crossCast); + case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: return sizeof(SmartAction::randTimedActionList); + case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: return sizeof(SmartAction::randRangeTimedActionList); + case SMART_ACTION_RANDOM_MOVE: return sizeof(SmartAction::moveRandom); + case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: return sizeof(SmartAction::setunitByte); + case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: return sizeof(SmartAction::delunitByte); + case SMART_ACTION_INTERRUPT_SPELL: return sizeof(SmartAction::interruptSpellCasting); + case SMART_ACTION_SEND_GO_CUSTOM_ANIM: return sizeof(SmartAction::sendGoCustomAnim); + case SMART_ACTION_SET_DYNAMIC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_ADD_DYNAMIC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_REMOVE_DYNAMIC_FLAG: return sizeof(SmartAction::flag); + case SMART_ACTION_JUMP_TO_POS: return sizeof(SmartAction::jump); + case SMART_ACTION_SEND_GOSSIP_MENU: return sizeof(SmartAction::sendGossipMenu); + case SMART_ACTION_GO_SET_LOOT_STATE: return sizeof(SmartAction::setGoLootState); + case SMART_ACTION_SEND_TARGET_TO_TARGET: return sizeof(SmartAction::sendTargetToTarget); + case SMART_ACTION_SET_HOME_POS: return NO_PARAMS; + case SMART_ACTION_SET_HEALTH_REGEN: return sizeof(SmartAction::setHealthRegen); + case SMART_ACTION_SET_ROOT: return sizeof(SmartAction::setRoot); + case SMART_ACTION_SET_GO_FLAG: return sizeof(SmartAction::goFlag); + case SMART_ACTION_ADD_GO_FLAG: return sizeof(SmartAction::goFlag); + case SMART_ACTION_REMOVE_GO_FLAG: return sizeof(SmartAction::goFlag); + case SMART_ACTION_SUMMON_CREATURE_GROUP: return sizeof(SmartAction::creatureGroup); + case SMART_ACTION_SET_POWER: return sizeof(SmartAction::power); + case SMART_ACTION_ADD_POWER: return sizeof(SmartAction::power); + case SMART_ACTION_REMOVE_POWER: return sizeof(SmartAction::power); + case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop); + case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart); + case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList); + case SMART_ACTION_MOVE_OFFSET: return NO_PARAMS; + case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound); + case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay); + case SMART_ACTION_DISABLE_EVADE: return sizeof(SmartAction::disableEvade); + case SMART_ACTION_GO_SET_GO_STATE: return sizeof(SmartAction::goState); + case SMART_ACTION_SET_CAN_FLY: return sizeof(SmartAction::setFly); + case SMART_ACTION_REMOVE_AURAS_BY_TYPE: return sizeof(SmartAction::auraType); + case SMART_ACTION_SET_SIGHT_DIST: return sizeof(SmartAction::sightDistance); + case SMART_ACTION_FLEE: return sizeof(SmartAction::flee); + case SMART_ACTION_ADD_THREAT: return sizeof(SmartAction::threat); + case SMART_ACTION_LOAD_EQUIPMENT: return sizeof(SmartAction::loadEquipment); + case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT: return sizeof(SmartAction::randomTimedEvent); + case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS: return NO_PARAMS; + case SMART_ACTION_PAUSE_MOVEMENT: return sizeof(SmartAction::pauseMovement); + case SMART_ACTION_PLAY_ANIMKIT: return sizeof(SmartAction::animKit); + case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::scene); + case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::scene); + case SMART_ACTION_SPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn); + case SMART_ACTION_DESPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn); + case SMART_ACTION_RESPAWN_BY_SPAWNID: return sizeof(SmartAction::respawnData); + case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast); + case SMART_ACTION_PLAY_CINEMATIC: return sizeof(SmartAction::cinematic); + case SMART_ACTION_SET_MOVEMENT_SPEED: return sizeof(SmartAction::movementSpeed); + case SMART_ACTION_PLAY_SPELL_VISUAL_KIT: return sizeof(SmartAction::spellVisualKit); + case SMART_ACTION_OVERRIDE_LIGHT: return sizeof(SmartAction::overrideLight); + case SMART_ACTION_OVERRIDE_WEATHER: return sizeof(SmartAction::overrideWeather); + case SMART_ACTION_SET_AI_ANIM_KIT: return NO_PARAMS; + case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover); + case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct); + case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::conversation); + //case SMART_ACTION_SET_IMMUNE_PC: return sizeof(SmartAction::raw); + //case SMART_ACTION_SET_IMMUNE_NPC: return sizeof(SmartAction::raw); + //case SMART_ACTION_SET_UNINTERACTIBLE: return sizeof(SmartAction::raw); + //case SMART_ACTION_ACTIVATE_GAMEOBJECT: return sizeof(SmartAction::raw); + case SMART_ACTION_ADD_TO_STORED_TARGET_LIST: return sizeof(SmartAction::addToStoredTargets); + case SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER: return sizeof(SmartAction::becomePersonalClone); + default: + TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return sizeof(SmartAction::raw); + } + }(); + + static size_t rawCount = sizeof(SmartAction::raw) / sizeof(uint32); + size_t paramsCount = paramsStructSize / sizeof(uint32); + + bool valid = true; + for (size_t index = paramsCount; index < rawCount; index++) + { + uint32 value = ((uint32*)&e.action.raw)[index]; + if (value != 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has unused action_param%zu with value %u, it must be 0, skipped.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value); + valid = false; + } + } + + return valid; +} + +bool SmartAIMgr::CheckUnusedTargetParams(SmartScriptHolder const& e) +{ + size_t paramsStructSize = [&]() -> size_t + { + constexpr size_t NO_PARAMS = size_t(0); + switch (e.target.type) + { + case SMART_TARGET_NONE: return NO_PARAMS; + case SMART_TARGET_SELF: return NO_PARAMS; + case SMART_TARGET_VICTIM: return NO_PARAMS; + case SMART_TARGET_HOSTILE_SECOND_AGGRO: return sizeof(SmartTarget::hostilRandom); + case SMART_TARGET_HOSTILE_LAST_AGGRO: return sizeof(SmartTarget::hostilRandom); + case SMART_TARGET_HOSTILE_RANDOM: return sizeof(SmartTarget::hostilRandom); + case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: return sizeof(SmartTarget::hostilRandom); + case SMART_TARGET_ACTION_INVOKER: return NO_PARAMS; + case SMART_TARGET_POSITION: return NO_PARAMS; //uses x,y,z,o + case SMART_TARGET_CREATURE_RANGE: return sizeof(SmartTarget::unitRange); + case SMART_TARGET_CREATURE_GUID: return sizeof(SmartTarget::unitGUID); + case SMART_TARGET_CREATURE_DISTANCE: return sizeof(SmartTarget::unitDistance); + case SMART_TARGET_STORED: return sizeof(SmartTarget::stored); + case SMART_TARGET_GAMEOBJECT_RANGE: return sizeof(SmartTarget::goRange); + case SMART_TARGET_GAMEOBJECT_GUID: return sizeof(SmartTarget::goGUID); + case SMART_TARGET_GAMEOBJECT_DISTANCE: return sizeof(SmartTarget::goDistance); + case SMART_TARGET_INVOKER_PARTY: return NO_PARAMS; + case SMART_TARGET_PLAYER_RANGE: return sizeof(SmartTarget::playerRange); + case SMART_TARGET_PLAYER_DISTANCE: return sizeof(SmartTarget::playerDistance); + case SMART_TARGET_CLOSEST_CREATURE: return sizeof(SmartTarget::unitClosest); + case SMART_TARGET_CLOSEST_GAMEOBJECT: return sizeof(SmartTarget::goClosest); + case SMART_TARGET_CLOSEST_PLAYER: return sizeof(SmartTarget::playerDistance); + case SMART_TARGET_ACTION_INVOKER_VEHICLE: return NO_PARAMS; + case SMART_TARGET_OWNER_OR_SUMMONER: return sizeof(SmartTarget::owner); + case SMART_TARGET_THREAT_LIST: return sizeof(SmartTarget::threatList); + case SMART_TARGET_CLOSEST_ENEMY: return sizeof(SmartTarget::closestAttackable); + case SMART_TARGET_CLOSEST_FRIENDLY: return sizeof(SmartTarget::closestFriendly); + case SMART_TARGET_LOOT_RECIPIENTS: return NO_PARAMS; + case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest); + case SMART_TARGET_VEHICLE_PASSENGER: return sizeof(SmartTarget::vehicle); + case SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT: return sizeof(SmartTarget::goClosest); + default: + TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u is using a target with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return sizeof(SmartTarget::raw); + } + }(); + + static size_t rawCount = sizeof(SmartTarget::raw) / sizeof(uint32); + size_t paramsCount = paramsStructSize / sizeof(uint32); + + bool valid = true; + for (size_t index = paramsCount; index < rawCount; index++) + { + uint32 value = ((uint32*)&e.target.raw)[index]; + if (value != 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has unused target_param%zu with value %u, it must be 0, skipped.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value); + valid = false; + } + } + + return valid; +} + bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) { if (e.event.type >= SMART_EVENT_END) @@ -1196,15 +1560,20 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } } + if (!CheckUnusedEventParams(e)) + return false; + switch (e.GetActionType()) { case SMART_ACTION_TALK: TC_SAI_IS_BOOLEAN_VALID(e, e.action.talk.useTalkTarget); - [[fallthrough]]; - case SMART_ACTION_SIMPLE_TALK: if (!IsTextValid(e, e.action.talk.textGroupID)) return false; break; + case SMART_ACTION_SIMPLE_TALK: + if (!IsTextValid(e, e.action.simpleTalk.textGroupID)) + return false; + break; case SMART_ACTION_SET_FACTION: if (e.action.faction.factionID && !sFactionTemplateStore.LookupEntry(e.action.faction.factionID)) { @@ -1360,10 +1729,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } [[fallthrough]]; case SMART_ACTION_SELF_CAST: - case SMART_ACTION_ADD_AURA: if (!IsSpellValid(e, e.action.cast.spell)) return false; break; + case SMART_ACTION_ADD_AURA: + if (!IsSpellValid(e, e.action.addAura.spell)) + return false; + break; case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: case SMART_ACTION_CALL_GROUPEVENTHAPPENS: if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest)) @@ -1574,7 +1946,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: { - if (!IsMinMaxValid(e, e.action.randTimedActionList.actionLists[0], e.action.randTimedActionList.actionLists[1])) + if (!IsMinMaxValid(e, e.action.randRangeTimedActionList.idMin, e.action.randRangeTimedActionList.idMax)) return false; break; } @@ -1937,6 +2309,11 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) TC_SAI_IS_BOOLEAN_VALID(e, e.action.evade.toRespawnPosition); break; } + case SMART_ACTION_SET_HEALTH_REGEN: + { + TC_SAI_IS_BOOLEAN_VALID(e, e.action.setHealthRegen.regenHealth); + break; + } case SMART_ACTION_CREATE_CONVERSATION: { if (!sConversationDataStore->GetConversationTemplate(e.action.conversation.id)) @@ -1992,7 +2369,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_GO_SET_GO_STATE: case SMART_ACTION_SEND_TARGET_TO_TARGET: case SMART_ACTION_SET_HOME_POS: - case SMART_ACTION_SET_HEALTH_REGEN: case SMART_ACTION_SET_GO_FLAG: case SMART_ACTION_ADD_GO_FLAG: case SMART_ACTION_REMOVE_GO_FLAG: @@ -2022,6 +2398,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; } + if (!CheckUnusedActionParams(e)) + return false; + return true; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index bc08fc25022..e9745753bb5 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -313,14 +313,6 @@ struct SmartEvent struct { - uint32 spell; - uint32 count; - uint32 repeatMin; - uint32 repeatMax; - } targetAura; - - struct - { uint32 type; uint32 id; } movementInform; @@ -385,12 +377,6 @@ struct SmartEvent struct { - uint32 spell; - uint32 effIndex; - } dummy; - - struct - { uint32 phasemask; } eventPhaseChange; @@ -447,11 +433,6 @@ struct SmartEvent struct { - uint32 sceneId; - } scene; - - struct - { uint32 param1; uint32 param2; uint32 param3; @@ -660,6 +641,12 @@ struct SmartAction struct { + uint32 textGroupID; + uint32 duration; + } simpleTalk; + + struct + { uint32 factionID; } faction; @@ -739,23 +726,9 @@ struct SmartAction struct { - uint32 flag1; - uint32 flag2; - uint32 flag3; - uint32 flag4; - uint32 flag5; - uint32 flag6; - } addUnitFlag; - - struct - { - uint32 flag1; - uint32 flag2; - uint32 flag3; - uint32 flag4; - uint32 flag5; - uint32 flag6; - } removeUnitFlag; + uint32 threatINC; + uint32 threatDEC; + } threat; struct { @@ -781,6 +754,11 @@ struct SmartAction struct { uint32 spell; + } addAura; + + struct + { + uint32 spell; uint32 charges; SAIBool onlyOwnedAuras; } removeAura; @@ -969,12 +947,6 @@ struct SmartAction struct { uint32 id; - uint32 number; - } storeVar; - - struct - { - uint32 id; } storeTargets; struct @@ -1009,6 +981,11 @@ struct SmartAction struct { + uint32 flag; + } flag; + + struct + { uint32 byte1; uint32 type; } setunitByte; @@ -1021,11 +998,6 @@ struct SmartAction struct { - uint32 seat; - } enterVehicle; - - struct - { uint32 id; uint32 timerType; SAIBool allowOverride; @@ -1038,6 +1010,12 @@ struct SmartAction struct { + uint32 idMin; + uint32 idMax; + } randRangeTimedActionList; + + struct + { SAIBool withDelayed; uint32 spell_id; SAIBool withInstant; @@ -1101,7 +1079,7 @@ struct SmartAction struct { - uint32 regenHealth; + SAIBool regenHealth; } setHealthRegen; struct @@ -1148,7 +1126,7 @@ struct SmartAction struct { - uint32 sounds[SMART_ACTION_PARAM_COUNT - 2]; + uint32 sounds[4]; SAIBool onlySelf; uint32 distance; } randomSound; @@ -1446,15 +1424,16 @@ struct SmartTarget struct { - uint32 map; - } position; + uint32 entry; + uint32 dist; + SAIBool dead; + } unitClosest; struct { uint32 entry; uint32 dist; - SAIBool dead; - } closest; + } goClosest; struct { @@ -1475,16 +1454,21 @@ struct SmartTarget struct { + uint32 seatMask; + } vehicle; + + struct + { + uint32 maxDist; + } threatList; + + struct + { uint32 param1; uint32 param2; uint32 param3; uint32 param4; } raw; - - struct - { - uint32 seatMask; - } vehicle; }; }; @@ -1791,6 +1775,10 @@ class TC_GAME_API SmartAIMgr static bool IsSpellVisualKitValid(SmartScriptHolder const& e, uint32 entry); static bool IsTextValid(SmartScriptHolder const& e, uint32 id); + static bool CheckUnusedEventParams(SmartScriptHolder const& e); + static bool CheckUnusedActionParams(SmartScriptHolder const& e); + static bool CheckUnusedTargetParams(SmartScriptHolder const& e); + // Helpers void LoadHelperStores(); void UnLoadHelperStores(); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp index d96ed002392..9fad909cd62 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp @@ -30,7 +30,6 @@ #include "QuestDef.h" #include "ScriptedGossip.h" #include "ScriptMgr.h" -#include "SmartAI.h" #include "SpellInfo.h" #include "SplineChainMovementGenerator.h" #include "StringFormat.h" |