From 23976aada77cf02a66e258ad6da62311fd75314f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 3 Oct 2026 14:34:05 +0200 Subject: [PATCH] Ship mounts: delete EquipmentHardpoints and the plan's Equipment list The array's only reader was the dead SoundBank block in EntityInstance, which looked up a hardpoint transform and did nothing with it. ShipModPlan.Equipment, ShipModShips' assignment, the preview check, the FBX builder's HP.Equipment case and its smoke assertion all fed that one dead reader. An HP.Equipment node is now refused by the builder as an unknown hardpoint kind. Co-Authored-By: Claude Opus 5.5 --- Assets/Scripts/Editor/ShipModPreview.cs | 4 +--- Assets/Scripts/Editor/ShipPrefabAuthoring.cs | 8 +++----- Assets/Scripts/Editor/ShipPrefabAuthoringSmoke.cs | 4 +--- Assets/Scripts/Gameplay/EntityInstance.cs | 11 ----------- Assets/Scripts/Gameplay/ShipModShips.cs | 1 - Assets/Scripts/ServerShared/ShipModPlan.cs | 3 --- docs/ship-collection-authoring.md | 6 ++---- tests/Aetheria.Shared.Tests/ShipModPlanTests.cs | 1 - 8 files changed, 7 insertions(+), 31 deletions(-) diff --git a/Assets/Scripts/Editor/ShipModPreview.cs b/Assets/Scripts/Editor/ShipModPreview.cs index 3cd6a05d0..44d419d92 100644 --- a/Assets/Scripts/Editor/ShipModPreview.cs +++ b/Assets/Scripts/Editor/ShipModPreview.cs @@ -53,7 +53,7 @@ public static class ShipModPreview var clone = UnityEngine.Object.Instantiate(ship.gameObject).GetComponent(); try { CheckShip(clone, plan, "clone"); } finally { UnityEngine.Object.DestroyImmediate(clone.gameObject); } - Debug.Log($"SHIP_MOD_ASSEMBLY_SMOKE equipment={plan.Equipment.Length} thrusters={plan.Thrusters.Length} " + + Debug.Log($"SHIP_MOD_ASSEMBLY_SMOKE thrusters={plan.Thrusters.Length} " + $"weapons={plan.Weapons.Length} radiators={plan.Radiators.Length}"); } @@ -64,8 +64,6 @@ public static class ShipModPreview Require(ship.HullColliders.Length == 1 && Inside(ship.HullColliders[0]) && ship.HullColliders[0].GetComponent() != null, "one hull collider with a MeshCollider"); Require(Inside(ship.MapIcon) && Inside(ship.Shield) && Inside(ship.TractorBeam), "map icon, shield and tractor inside the ship"); - Require(ship.EquipmentHardpoints.Select(node => node.name).SequenceEqual(plan.Equipment) && - ship.EquipmentHardpoints.All(Inside), "equipment hardpoints named by the plan"); Require(ship.ThrusterHardpoints.Select(node => node.name).SequenceEqual(plan.Thrusters) && ship.ThrusterHardpoints.All(node => Inside(node) && Inside(node.Emitter)), "thruster hardpoints with emitters"); Require(ship.RadiatorHardpoints.Select(node => node.name).SequenceEqual(plan.Radiators) && diff --git a/Assets/Scripts/Editor/ShipPrefabAuthoring.cs b/Assets/Scripts/Editor/ShipPrefabAuthoring.cs index 988fe15e7..8a419c6e0 100644 --- a/Assets/Scripts/Editor/ShipPrefabAuthoring.cs +++ b/Assets/Scripts/Editor/ShipPrefabAuthoring.cs @@ -92,7 +92,7 @@ public static class ShipPrefabAuthoring var combatLayer = LayerMask.NameToLayer("Combat"); if (minimapLayer < 0 || combatLayer < 0) throw new InvalidOperationException("Minimap or Combat layer is missing"); - var equipment = new List(); + var hardpoints = 0; var thrusters = new List(); var weapons = new List(); var radiators = new List(); @@ -106,10 +106,9 @@ public static class ShipPrefabAuthoring var parts = name.Split('.'); if (parts.Length != 3 || string.IsNullOrWhiteSpace(parts[2])) throw new InvalidOperationException($"Invalid hardpoint name {name}"); - equipment.Add(node); + hardpoints++; switch (parts[1]) { - case "Equipment": break; case "Thruster": var emitter = DirectChild(node, "Emitter")?.GetComponent(); if (emitter == null) throw new InvalidOperationException($"{name} needs an Emitter mesh child"); @@ -155,7 +154,7 @@ public static class ShipPrefabAuthoring name != "SHIP.Shield" && name != "SHIP.TractorBeam") throw new InvalidOperationException($"Unknown ship anchor {name}"); } - if (equipment.Count == 0) throw new InvalidOperationException("Ship has no HP.* hardpoints"); + if (hardpoints == 0) throw new InvalidOperationException("Ship has no HP.* hardpoints"); mapIcon.sharedMaterial = mapMaterial; mapIcon.gameObject.layer = minimapLayer; @@ -182,7 +181,6 @@ public static class ShipPrefabAuthoring ship.InvisibleMaterial = invisible; ship.Shield = shield; ship.HullColliders = new[] { hullSurface }; - ship.EquipmentHardpoints = equipment.ToArray(); ship.ThrusterHardpoints = thrusters.ToArray(); ship.WeaponHardpoints = weapons.ToArray(); ship.RadiatorHardpoints = radiators.ToArray(); diff --git a/Assets/Scripts/Editor/ShipPrefabAuthoringSmoke.cs b/Assets/Scripts/Editor/ShipPrefabAuthoringSmoke.cs index adda9ff7d..34f5abf83 100644 --- a/Assets/Scripts/Editor/ShipPrefabAuthoringSmoke.cs +++ b/Assets/Scripts/Editor/ShipPrefabAuthoringSmoke.cs @@ -23,13 +23,11 @@ public static class ShipPrefabAuthoringSmoke Child(weapon.gameObject, "Muzzle.0"); var radiator = Child(root, "HP.Radiator.Port"); Primitive(radiator.gameObject, "RadiatorMesh"); - Child(root, "HP.Equipment.Reactor"); Child(root, "Pivot.2.-90.90.-80.80.60"); ShipPrefabAuthoring.Configure(root); var ship = root.GetComponent(); - Require(ship != null && ship.EquipmentHardpoints.Length == 4, "equipment references"); - Require(ship.ThrusterHardpoints.Length == 1 && ship.ThrusterHardpoints[0].Emitter != null, "thruster emitter"); + Require(ship != null && ship.ThrusterHardpoints.Length == 1 && ship.ThrusterHardpoints[0].Emitter != null, "thruster emitter"); Require(ship.WeaponHardpoints.Length == 1 && ship.WeaponHardpoints[0].FiringPoint.Length == 2, "weapon muzzles"); Require(ship.WeaponHardpoints[0].FiringPoint[0].name == "Muzzle.0", "numeric muzzle order"); Require(ship.RadiatorHardpoints.Length == 1 && ship.RadiatorHardpoints[0].Mesh != null, "radiator mesh"); diff --git a/Assets/Scripts/Gameplay/EntityInstance.cs b/Assets/Scripts/Gameplay/EntityInstance.cs index f3d977c8c..af80d8c2d 100644 --- a/Assets/Scripts/Gameplay/EntityInstance.cs +++ b/Assets/Scripts/Gameplay/EntityInstance.cs @@ -20,7 +20,6 @@ public class EntityInstance : MonoBehaviour public ShieldManager Shield; public HullCollider[] HullColliders; - public Transform[] EquipmentHardpoints; public RadiatorHardpoint[] RadiatorHardpoints; public ThrusterHardpoint[] ThrusterHardpoints; public WeaponHardpoint[] WeaponHardpoints; @@ -241,16 +240,6 @@ public class EntityInstance : MonoBehaviour _constantWeaponManagers[data].StopFiring(item); } } - - var hp = Entity.Hardpoints[item.Position.x, item.Position.y]; - if (hp != null && item.Data.SoundBank != 0) - { - var hardpointTransform = EquipmentHardpoints.FirstOrDefault(x => x.name == hp.Transform); - if (hardpointTransform != null) - { - var hardpointGameObject = hardpointTransform.gameObject; - } - } } RadiatorMeshes = new Dictionary(); Barrels = new Dictionary(); diff --git a/Assets/Scripts/Gameplay/ShipModShips.cs b/Assets/Scripts/Gameplay/ShipModShips.cs index 26761ad11..9e06099c9 100644 --- a/Assets/Scripts/Gameplay/ShipModShips.cs +++ b/Assets/Scripts/Gameplay/ShipModShips.cs @@ -149,7 +149,6 @@ public static class ShipModShips instance.InvisibleMaterial = template.Invisible; instance.Shield = shield; instance.HullColliders = new[] { surface }; - instance.EquipmentHardpoints = plan.Equipment.Select(Node).ToArray(); instance.ThrusterHardpoints = thrusters; instance.WeaponHardpoints = weapons; instance.RadiatorHardpoints = radiators; diff --git a/Assets/Scripts/ServerShared/ShipModPlan.cs b/Assets/Scripts/ServerShared/ShipModPlan.cs index 6b696bcaa..787656a3e 100644 --- a/Assets/Scripts/ServerShared/ShipModPlan.cs +++ b/Assets/Scripts/ServerShared/ShipModPlan.cs @@ -10,8 +10,6 @@ public sealed class ShipModPlan public string HullCollider; public string Shield; public string Tractor; - // Every hull hardpoint's mount id, in hardpoint order: the anchor node each one is matched to by name. - public string[] Equipment; // Mount ids whose anchor (role thruster-emitter / radiator-mesh) is the emitter / mesh node itself. public string[] Thrusters; public string[] Radiators; @@ -53,7 +51,6 @@ public sealed class ShipModPlan HullCollider = Only("hull-collider"), Shield = Only("shield"), Tractor = Only("tractor"), - Equipment = hardpoints.Select(hardpoint => hardpoint.Transform).ToArray(), Thrusters = Mounts(HardpointType.Thruster), Radiators = Mounts(HardpointType.Radiator), Weapons = weapons diff --git a/docs/ship-collection-authoring.md b/docs/ship-collection-authoring.md index a92551ccd..198a083dc 100644 --- a/docs/ship-collection-authoring.md +++ b/docs/ship-collection-authoring.md @@ -44,13 +44,11 @@ reserved. IDs after a role prefix must be unique across the model. Other visual Muzzle.1 optional additional barrel HP.Radiator.Port empty; exact name copied to the catalog RadiatorMesh one mesh; temperature emission surface - HP.Equipment.Reactor empty; exact name copied to the catalog Pivot.0.-90.90.-80.80.60 optional empty parent of articulated mounts ``` -`HP.Equipment` covers sensors, reactor, shield, cargo, and other mounts without a special visual component. -`HP.Weapon` covers ballistic, energy, and launcher mounts; the catalog chooses which. Every `HP.*` becomes an -`EquipmentHardpoints` entry. Thruster, weapon, and radiator roles also get their matching components and arrays. +`HP.Weapon` covers ballistic, energy, and launcher mounts; the catalog chooses which. Only thrusters, weapons and +radiators are visible and get a node; internal hardpoints have none. Each role gets its matching component and array. `Muzzle.` children are sorted numerically; their transforms become `FiringPoint`. A weapon mount requires at least one. A `Pivot` name carries `Group.YawMin.YawMax.PitchMin.PitchMax.Speed` as signed integers in degrees and degrees per second. It gets `ArticulationPoint`; child mounts follow its transform. Pivots are diff --git a/tests/Aetheria.Shared.Tests/ShipModPlanTests.cs b/tests/Aetheria.Shared.Tests/ShipModPlanTests.cs index c98ff3a10..e44c60e83 100644 --- a/tests/Aetheria.Shared.Tests/ShipModPlanTests.cs +++ b/tests/Aetheria.Shared.Tests/ShipModPlanTests.cs @@ -33,7 +33,6 @@ public sealed class ShipModPlanTests var plan = Plan(Rig()); Assert.Equal(("map", "collider", "shield", "tractor"), (plan.MapIcon, plan.HullCollider, plan.Shield, plan.Tractor)); - Assert.Equal(new[] { "thruster.port", "gun", "fin" }, plan.Equipment); Assert.Equal(new[] { "thruster.port" }, plan.Thrusters); Assert.Equal(new[] { "fin" }, plan.Radiators); var (mount, muzzles) = Assert.Single(plan.Weapons);