2026-09-30 06:43:52 +02:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
// Which anchor fills which slot of a ship's component arrays. Pure over (hull, visual) so the Unity assembler only
|
|
|
|
|
// follows it: the hull's hardpoint type decides what a mount is, the anchor's role decides which node plays the part.
|
|
|
|
|
public sealed class ShipModPlan
|
|
|
|
|
{
|
|
|
|
|
public string MapIcon;
|
|
|
|
|
public string HullCollider;
|
|
|
|
|
public string Shield;
|
|
|
|
|
public string Tractor;
|
|
|
|
|
// Mount ids whose anchor (role thruster-emitter / radiator-mesh) is the emitter / mesh node itself.
|
|
|
|
|
public string[] Thrusters;
|
|
|
|
|
public string[] Radiators;
|
2026-10-03 14:39:08 +02:00
|
|
|
// Each weapon mount (role weapon-mount) and its muzzle anchors, by Order then id.
|
2026-09-30 06:43:52 +02:00
|
|
|
public (string Mount, string[] Muzzles)[] Weapons;
|
|
|
|
|
|
2026-10-03 14:39:08 +02:00
|
|
|
// Maps a pair Validate accepts; every rule about which anchor may play which part is Validate's, so this refuses nothing.
|
2026-09-30 06:43:52 +02:00
|
|
|
public static ShipModPlan Build(HullData hull, ShipAuthoring visual)
|
|
|
|
|
{
|
|
|
|
|
ShipAuthoringStore.Validate(hull, visual);
|
|
|
|
|
var hardpoints = hull.Hardpoints ?? new List<HardpointData>();
|
|
|
|
|
string Only(string wanted) => visual.Anchors.Single(anchor => anchor.Role == wanted).Id;
|
Ship S2 fixes: structural anchors are not mounts, mod presets refused, one bad mod never bricks the boot
- Validate: a hardpoint's anchor role is fixed by its type (thruster-emitter, radiator-mesh, else articulation); ShipModPlan's
duplicate role check is deleted.
- Loadouts.Commit refuses a preset naming a mod design (mod-hull:/mod-ship:), so the shipped catalog never references a mod.
- Compose quarantines each package: a bad package is excluded and named, a collision excludes every package involved; the
game boots on the rest (or the shipped catalog) and the main menu lists the exclusions.
- RequireDesigns refuses a save with a null item or lot instead of throwing NullReferenceException.
- Tests: per structural role, muzzle id ties, every slot/zone/lot in RequireDesigns, listing order, exclusion cases.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 08:30:52 +02:00
|
|
|
string[] Mounts(HardpointType type) => hardpoints.Where(hardpoint => hardpoint.Type == type).Select(hardpoint => hardpoint.Transform).ToArray();
|
2026-09-30 06:43:52 +02:00
|
|
|
var muzzles = visual.Anchors.Where(anchor => anchor.Role == "weapon-muzzle")
|
|
|
|
|
.OrderBy(anchor => anchor.Order).ThenBy(anchor => anchor.Id, StringComparer.Ordinal).ToArray();
|
|
|
|
|
|
|
|
|
|
return new ShipModPlan
|
|
|
|
|
{
|
|
|
|
|
MapIcon = Only("map-icon"),
|
|
|
|
|
HullCollider = Only("hull-collider"),
|
|
|
|
|
Shield = Only("shield"),
|
|
|
|
|
Tractor = Only("tractor"),
|
Ship S2 fixes: structural anchors are not mounts, mod presets refused, one bad mod never bricks the boot
- Validate: a hardpoint's anchor role is fixed by its type (thruster-emitter, radiator-mesh, else articulation); ShipModPlan's
duplicate role check is deleted.
- Loadouts.Commit refuses a preset naming a mod design (mod-hull:/mod-ship:), so the shipped catalog never references a mod.
- Compose quarantines each package: a bad package is excluded and named, a collision excludes every package involved; the
game boots on the rest (or the shipped catalog) and the main menu lists the exclusions.
- RequireDesigns refuses a save with a null item or lot instead of throwing NullReferenceException.
- Tests: per structural role, muzzle id ties, every slot/zone/lot in RequireDesigns, listing order, exclusion cases.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 08:30:52 +02:00
|
|
|
Thrusters = Mounts(HardpointType.Thruster),
|
|
|
|
|
Radiators = Mounts(HardpointType.Radiator),
|
2026-10-03 14:39:08 +02:00
|
|
|
Weapons = hardpoints.Where(hardpoint => ShipAuthoringStore.IsWeapon(hardpoint.Type)).Select(hardpoint => (
|
|
|
|
|
hardpoint.Transform,
|
|
|
|
|
muzzles.Where(muzzle => muzzle.ParentId == hardpoint.Transform).Select(muzzle => muzzle.Id).ToArray())).ToArray()
|
2026-09-30 06:43:52 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|