From 8433bc09489947314e88f16b5965d1e56d5c58c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Fri, 19 May 2023 16:21:25 +0200 Subject: [PATCH] Throw early when Lua function parameters are null. --- OpenRA.Game/Scripting/ScriptMemberWrapper.cs | 2 +- .../Scripting/Global/TriggerGlobal.cs | 143 +++++++++++++----- 2 files changed, 110 insertions(+), 35 deletions(-) diff --git a/OpenRA.Game/Scripting/ScriptMemberWrapper.cs b/OpenRA.Game/Scripting/ScriptMemberWrapper.cs index 5224621cd1..951e74a914 100644 --- a/OpenRA.Game/Scripting/ScriptMemberWrapper.cs +++ b/OpenRA.Game/Scripting/ScriptMemberWrapper.cs @@ -50,7 +50,7 @@ namespace OpenRA.Scripting try { if (!IsMethod) - throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!"); + throw new LuaException($"Trying to invoke a {nameof(ScriptMemberWrapper)} that isn't a method!"); var mi = (MethodInfo)Member; var pi = mi.GetParameters(); diff --git a/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs index 0991e980dd..7fd63addcb 100644 --- a/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs +++ b/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs @@ -23,11 +23,11 @@ namespace OpenRA.Mods.Common.Scripting public TriggerGlobal(ScriptContext context) : base(context) { } - public static ScriptTriggers GetScriptTriggers(Actor a) + public static ScriptTriggers GetScriptTriggers(Actor actor) { - var events = a.TraitOrDefault(); + var events = actor.TraitOrDefault(); if (events == null) - throw new LuaException($"Actor '{a.Info.Name}' requires the ScriptTriggers trait before attaching a trigger"); + throw new LuaException($"Actor '{actor.Info.Name}' requires the ScriptTriggers trait before attaching a trigger"); return events; } @@ -54,43 +54,61 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Call a function for each passenger when it enters a transport. " + "The callback function will be called as func(Actor transport, Actor passenger).")] - public void OnPassengerEntered(Actor a, LuaFunction func) + public void OnPassengerEntered(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnPassengerEntered, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnPassengerEntered, func, Context); } [Desc("Call a function for each passenger when it exits a transport. " + "The callback function will be called as func(Actor transport, Actor passenger).")] - public void OnPassengerExited(Actor a, LuaFunction func) + public void OnPassengerExited(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnPassengerExited, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnPassengerExited, func, Context); } [Desc("Call a function each tick that the actor is idle. " + "The callback function will be called as func(Actor self).")] - public void OnIdle(Actor a, LuaFunction func) + public void OnIdle(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnIdle, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnIdle, func, Context); } [Desc("Call a function when the actor is damaged. The callback " + "function will be called as func(Actor self, Actor attacker, int damage).")] - public void OnDamaged(Actor a, LuaFunction func) + public void OnDamaged(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnDamaged, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnDamaged, func, Context); } [Desc("Call a function when the actor is killed. The callback " + "function will be called as func(Actor self, Actor killer).")] - public void OnKilled(Actor a, LuaFunction func) + public void OnKilled(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnKilled, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnKilled, func, Context); } [Desc("Call a function when all of the actors in a group are killed. The callback " + "function will be called as func().")] public void OnAllKilled(Actor[] actors, LuaFunction func) { + if (actors == null) + throw new NullReferenceException(nameof(actors)); + var group = actors.ToList(); var f = (LuaFunction)func.CopyReference(); void OnMemberKilled(Actor m) @@ -137,15 +155,21 @@ namespace OpenRA.Mods.Common.Scripting } } + if (actors == null) + throw new NullReferenceException(nameof(actors)); + foreach (var a in actors) GetScriptTriggers(a).OnKilledInternal += OnMemberKilled; } [Desc("Call a function when this actor produces another actor. " + "The callback function will be called as func(Actor producer, Actor produced).")] - public void OnProduction(Actor a, LuaFunction func) + public void OnProduction(Actor actors, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnProduction, func, Context); + if (actors == null) + throw new NullReferenceException(nameof(actors)); + + GetScriptTriggers(actors).RegisterCallback(Trigger.OnProduction, func, Context); } [Desc("Call a function when any actor produces another actor. The callback " + @@ -159,6 +183,9 @@ namespace OpenRA.Mods.Common.Scripting "The callback function will be called as func(Player player).")] public void OnPlayerWon(Player player, LuaFunction func) { + if (player == null) + throw new NullReferenceException(nameof(player)); + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerWon, func, Context); } @@ -166,6 +193,9 @@ namespace OpenRA.Mods.Common.Scripting "The callback function will be called as func(Player player).")] public void OnPlayerLost(Player player, LuaFunction func) { + if (player == null) + throw new NullReferenceException(nameof(player)); + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerLost, func, Context); } @@ -173,6 +203,9 @@ namespace OpenRA.Mods.Common.Scripting "The callback function will be called as func(Player player, int objectiveID).")] public void OnObjectiveAdded(Player player, LuaFunction func) { + if (player == null) + throw new NullReferenceException(nameof(player)); + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveAdded, func, Context); } @@ -180,6 +213,9 @@ namespace OpenRA.Mods.Common.Scripting "The callback function will be called as func(Player player, int objectiveID).")] public void OnObjectiveCompleted(Player player, LuaFunction func) { + if (player == null) + throw new NullReferenceException(nameof(player)); + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveCompleted, func, Context); } @@ -187,27 +223,39 @@ namespace OpenRA.Mods.Common.Scripting "The callback function will be called as func(Player player, int objectiveID).")] public void OnObjectiveFailed(Player player, LuaFunction func) { + if (player == null) + throw new NullReferenceException(nameof(player)); + GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveFailed, func, Context); } [Desc("Call a function when this actor is added to the world. " + "The callback function will be called as func(Actor self).")] - public void OnAddedToWorld(Actor a, LuaFunction func) + public void OnAddedToWorld(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnAddedToWorld, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnAddedToWorld, func, Context); } [Desc("Call a function when this actor is removed from the world. " + "The callback function will be called as func(Actor self).")] - public void OnRemovedFromWorld(Actor a, LuaFunction func) + public void OnRemovedFromWorld(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnRemovedFromWorld, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnRemovedFromWorld, func, Context); } [Desc("Call a function when all of the actors in a group have been removed from the world. " + "The callback function will be called as func().")] public void OnAllRemovedFromWorld(Actor[] actors, LuaFunction func) { + if (actors == null) + throw new NullReferenceException(nameof(actors)); + var group = actors.ToList(); var f = (LuaFunction)func.CopyReference(); @@ -256,14 +304,17 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Call a function when this actor is captured. The callback function " + "will be called as func(Actor self, Actor captor, Player oldOwner, Player newOwner).")] - public void OnCapture(Actor a, LuaFunction func) + public void OnCapture(Actor actors, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnCapture, func, Context); + if (actors == null) + throw new NullReferenceException(nameof(actors)); + + GetScriptTriggers(actors).RegisterCallback(Trigger.OnCapture, func, Context); } [Desc("Call a function when this actor is killed or captured. " + "The callback function will be called as func().")] - public void OnKilledOrCaptured(Actor a, LuaFunction func) + public void OnKilledOrCaptured(Actor actor, LuaFunction func) { var called = false; @@ -286,14 +337,20 @@ namespace OpenRA.Mods.Common.Scripting } } - GetScriptTriggers(a).OnCapturedInternal += OnKilledOrCaptured; - GetScriptTriggers(a).OnKilledInternal += OnKilledOrCaptured; + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).OnCapturedInternal += OnKilledOrCaptured; + GetScriptTriggers(actor).OnKilledInternal += OnKilledOrCaptured; } [Desc("Call a function when all of the actors in a group have been killed or captured. " + "The callback function will be called as func().")] public void OnAllKilledOrCaptured(Actor[] actors, LuaFunction func) { + if (actors == null) + throw new NullReferenceException(nameof(actors)); + var group = actors.ToList(); var f = (LuaFunction)func.CopyReference(); @@ -443,17 +500,23 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Call a function when this actor is infiltrated. The callback function " + "will be called as func(Actor self, Actor infiltrator).")] - public void OnInfiltrated(Actor a, LuaFunction func) + public void OnInfiltrated(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnInfiltrated, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnInfiltrated, func, Context); } [Desc("Call a function when this actor is discovered by an enemy or a player with a Neutral stance. " + "The callback function will be called as func(Actor discovered, Player discoverer). " + "The player actor needs the 'EnemyWatcher' trait. The actors to discover need the 'AnnounceOnSeen' trait.")] - public void OnDiscovered(Actor a, LuaFunction func) + public void OnDiscovered(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnDiscovered, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnDiscovered, func, Context); } [Desc("Call a function when this player is discovered by an enemy or neutral player. " + @@ -461,14 +524,20 @@ namespace OpenRA.Mods.Common.Scripting "The player actor needs the 'EnemyWatcher' trait. The actors to discover need the 'AnnounceOnSeen' trait.")] public void OnPlayerDiscovered(Player discovered, LuaFunction func) { + if (discovered == null) + throw new NullReferenceException(nameof(discovered)); + GetScriptTriggers(discovered.PlayerActor).RegisterCallback(Trigger.OnPlayerDiscovered, func, Context); } [Desc("Call a function when this actor is sold. The callback function " + "will be called as func(Actor self).")] - public void OnSold(Actor a, LuaFunction func) + public void OnSold(Actor actor, LuaFunction func) { - GetScriptTriggers(a).RegisterCallback(Trigger.OnSold, func, Context); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).RegisterCallback(Trigger.OnSold, func, Context); } [Desc("Call a function when the game timer expires. The callback function will be called as func().")] @@ -480,19 +549,25 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Removes all triggers from this actor. " + "Note that the removal will only take effect at the end of a tick, " + "so you must not add new triggers at the same time that you are calling this function.")] - public void ClearAll(Actor a) + public void ClearAll(Actor actor) { - GetScriptTriggers(a).ClearAll(); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).ClearAll(); } [Desc("Removes the specified trigger from this actor. " + "Note that the removal will only take effect at the end of a tick, " + "so you must not add new triggers at the same time that you are calling this function.")] - public void Clear(Actor a, string triggerName) + public void Clear(Actor actor, string triggerName) { var trigger = (Trigger)Enum.Parse(typeof(Trigger), triggerName); - GetScriptTriggers(a).Clear(trigger); + if (actor == null) + throw new NullReferenceException(nameof(actor)); + + GetScriptTriggers(actor).Clear(trigger); } } }