Files
OpenRA/OpenRA.Mods.Common/Lint/CheckInteractable.cs
Gustas 925e042455 Add Interactable lint test
Since # 19174 bounds are calculated from WDist instead of pixels. This causes many of the older maps to crash games, And this lint test makes it easier for map makers to detect these issues.

As calculating the bounds requires MapGrid, we need to write a separate lint test for Interactable instead of defaulting to RulesetLoaded checks.
2023-03-27 19:55:19 +02:00

72 lines
2.3 KiB
C#

#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
class CheckInteractable : ILintRulesPass, ILintServerMapPass
{
void ILintRulesPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, Ruleset rules)
{
Run(emitError, rules, modData);
}
void ILintServerMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
{
Run(emitError, mapRules, modData);
}
void Run(Action<string> emitError, Ruleset rules, ModData modData)
{
// As the map has not been created we need to get MapGrid info directly from manifest.
var grid = modData.Manifest.Get<MapGrid>();
var tileScale = grid.Type == MapGridType.RectangularIsometric ? 1448 : 1024;
foreach (var actorInfo in rules.Actors)
{
// Catch TypeDictionary errors.
try
{
var interactable = actorInfo.Value.TraitInfoOrDefault<InteractableInfo>();
if (interactable == null)
continue;
if (HasInvalidBounds(interactable.Bounds, grid.TileSize, tileScale))
emitError($"{nameof(interactable.Bounds)} of actor {actorInfo.Key} are empty or negative.");
if (HasInvalidBounds(interactable.DecorationBounds, grid.TileSize, tileScale))
emitError($"{nameof(interactable.DecorationBounds)} of actor {actorInfo.Key} are empty or negative.");
}
catch (InvalidOperationException e)
{
emitError($"{e.Message} (Actor type `{actorInfo.Key}`)");
}
}
}
static bool HasInvalidBounds(WDist[] bounds, Size tileSize, int tileScale)
{
if (bounds == null)
return false;
if (bounds.Length != 2 && bounds.Length != 4)
return true;
var size = new int2(bounds[0].Length * tileSize.Width / tileScale, bounds[1].Length * tileSize.Height / tileScale);
return size.X <= 0 || size.Y <= 0;
}
}
}