From 2b3d99fac2fd9878f150f179799438ea6405cda8 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 8 May 2020 12:55:22 +0200 Subject: [PATCH] Sanitize resource warheads - Fix potential crash due to invalid target (no CenterPosition) - Fix potential crash on multiple ResourceLayers --- .../Warheads/CreateResourceWarhead.cs | 37 +++++++++++-------- .../Warheads/DestroyResourceWarhead.cs | 6 ++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs b/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs index 9a2fe5f867..c16941c270 100644 --- a/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs +++ b/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs @@ -17,43 +17,50 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Warheads { - public class CreateResourceWarhead : Warhead + public class CreateResourceWarhead : Warhead, IRulesetLoaded { [Desc("Size of the area. The resources are seeded within this area.", "Provide 2 values for a ring effect (outer/inner).")] public readonly int[] Size = { 0, 0 }; [Desc("Will this splatter resources and which?")] + [FieldLoader.Require] public readonly string AddsResourceType = null; + void IRulesetLoaded.RulesetLoaded(Ruleset rules, WeaponInfo info) + { + var world = rules.Actors["world"]; + var resourceType = world.TraitInfos() + .FirstOrDefault(t => t.Type == AddsResourceType); + + if (resourceType == null) + throw new YamlException("CreateResourceWarhead defines an invalid resource type '{0}'".F(AddsResourceType)); + } + // TODO: Allow maximum resource splatter to be defined. (Per tile, and in total). public override void DoImpact(Target target, WarheadArgs args) { - if (string.IsNullOrEmpty(AddsResourceType)) + if (target.Type == TargetType.Invalid) return; var firedBy = args.SourceActor; + var pos = target.CenterPosition; var world = firedBy.World; - var targetTile = world.Map.CellContaining(target.CenterPosition); - var resLayer = world.WorldActor.Trait(); + var targetTile = world.Map.CellContaining(pos); var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0; var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]); var resourceType = world.WorldActor.TraitsImplementing() - .FirstOrDefault(t => t.Info.Type == AddsResourceType); + .First(t => t.Info.Type == AddsResourceType); - if (resourceType == null) - Log.Write("debug", "Warhead defines an invalid resource type '{0}'".F(AddsResourceType)); - else + var resLayer = world.WorldActor.Trait(); + foreach (var cell in allCells) { - foreach (var cell in allCells) - { - if (!resLayer.CanSpawnResourceAt(resourceType, cell)) - continue; + if (!resLayer.CanSpawnResourceAt(resourceType, cell)) + continue; - var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell)); - resLayer.AddResource(resourceType, cell, splash); - } + var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell)); + resLayer.AddResource(resourceType, cell, splash); } } } diff --git a/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs b/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs index fc3371a616..a505434e2e 100644 --- a/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs +++ b/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs @@ -24,9 +24,13 @@ namespace OpenRA.Mods.Common.Warheads // TODO: Allow maximum resource removal to be defined. (Per tile, and in total). public override void DoImpact(Target target, WarheadArgs args) { + if (target.Type == TargetType.Invalid) + return; + var firedBy = args.SourceActor; + var pos = target.CenterPosition; var world = firedBy.World; - var targetTile = world.Map.CellContaining(target.CenterPosition); + var targetTile = world.Map.CellContaining(pos); var resLayer = world.WorldActor.Trait(); var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;