using Sandbox.Definitions; using System.Text.RegularExpressions; using VRage.Game; namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore.BlueprintEditing; public enum BlueprintArmorType { Light, Heavy } public sealed class BlueprintTransformResult { public int ConvertedBlocks { get; internal set; } public int AlreadyTargetBlocks { get; internal set; } public int UnsupportedBlocks { get; internal set; } public int ChangedGrids { get; internal set; } } /// /// Converts blueprint blocks by using the definitions loaded from the installed game. /// This keeps the conversion table in sync with game and DLC updates. /// public static class BlueprintTransformService { private static readonly Regex ArmorWeightRegex = new( "(?:Light|Heavy)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); public static BlueprintTransformResult ConvertGridSize( MyObjectBuilder_ShipBlueprintDefinition blueprint, MyCubeSize targetSize) { if (blueprint is null) { throw new ArgumentNullException(nameof(blueprint)); } var result = new BlueprintTransformResult(); foreach (var grid in blueprint.CubeGrids ?? []) { if (grid.GridSizeEnum != targetSize) { grid.GridSizeEnum = targetSize; result.ChangedGrids++; } foreach (var block in grid.CubeBlocks ?? []) { var sourceDefinition = TryGetDefinition(block); if (sourceDefinition is null) { result.UnsupportedBlocks++; continue; } if (sourceDefinition.CubeSize == targetSize) { result.AlreadyTargetBlocks++; continue; } var group = MyDefinitionManager.Static.TryGetDefinitionGroup(sourceDefinition.BlockPairName); var targetDefinition = targetSize == MyCubeSize.Small ? group?.Small : group?.Large; if (targetDefinition is null || targetDefinition.Id.TypeId != block.TypeId) { result.UnsupportedBlocks++; continue; } block.SubtypeName = targetDefinition.Id.SubtypeName; result.ConvertedBlocks++; } } return result; } public static BlueprintTransformResult ConvertArmor( MyObjectBuilder_ShipBlueprintDefinition blueprint, BlueprintArmorType targetArmor) { if (blueprint is null) { throw new ArgumentNullException(nameof(blueprint)); } var targetIsHeavy = targetArmor == BlueprintArmorType.Heavy; var candidates = MyDefinitionManager.Static.GetAllDefinitions() .OfType() .Where(IsArmorDefinition) .GroupBy(definition => CreateArmorKey( definition.BlockPairName, definition.CubeSize, IsHeavyArmor(definition))) .ToDictionary(group => group.Key, group => group.First()); var result = new BlueprintTransformResult(); foreach (var grid in blueprint.CubeGrids ?? []) { foreach (var block in grid.CubeBlocks ?? []) { var sourceDefinition = TryGetDefinition(block); if (sourceDefinition is null || !IsArmorDefinition(sourceDefinition)) { continue; } if (IsHeavyArmor(sourceDefinition) == targetIsHeavy) { result.AlreadyTargetBlocks++; continue; } var key = CreateArmorKey( sourceDefinition.BlockPairName, sourceDefinition.CubeSize, targetIsHeavy); if (!candidates.TryGetValue(key, out var targetDefinition) || targetDefinition.Id.TypeId != block.TypeId) { result.UnsupportedBlocks++; continue; } block.SubtypeName = targetDefinition.Id.SubtypeName; result.ConvertedBlocks++; } } return result; } private static MyCubeBlockDefinition? TryGetDefinition(MyObjectBuilder_CubeBlock block) { try { return MyDefinitionManager.Static.GetCubeBlockDefinition(block); } catch { return null; } } private static bool IsArmorDefinition(MyCubeBlockDefinition definition) { return definition.BlockPairName.IndexOf("Armor", StringComparison.OrdinalIgnoreCase) >= 0 || definition.Id.SubtypeName.IndexOf("Armor", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsHeavyArmor(MyCubeBlockDefinition definition) { return definition.BlockPairName.IndexOf("Heavy", StringComparison.OrdinalIgnoreCase) >= 0 || definition.Id.SubtypeName.IndexOf("Heavy", StringComparison.OrdinalIgnoreCase) >= 0; } private static string NormalizeArmorName(string name) { return ArmorWeightRegex.Replace(name ?? string.Empty, string.Empty); } private static string CreateArmorKey(string pairName, MyCubeSize cubeSize, bool isHeavy) { return $"{NormalizeArmorName(pairName)}|{(int)cubeSize}|{isHeavy}"; } }