From 3e56eadeba51d65385a3f11e03505c82175faebd Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 15 Jun 2026 16:51:17 +0100 Subject: [PATCH] Delete legacy item data DTO hierarchy --- .voidbot/state/aetheria.cc | Bin 104323 -> 104703 bytes Aetheria.State/README.md | 8 +- Assets/Scripts/ServerShared/ItemData.cs | 600 ------------------ Assets/Scripts/ServerShared/ItemData.cs.meta | 3 - .../Scripts/ServerShared/RuntimeGeometry.cs | 328 ++++++++++ .../ServerShared/RuntimeGeometry.cs.meta | 3 + docs/aetheria-perfect-machine-map.md | 31 +- 7 files changed, 353 insertions(+), 620 deletions(-) delete mode 100644 Assets/Scripts/ServerShared/ItemData.cs delete mode 100644 Assets/Scripts/ServerShared/ItemData.cs.meta create mode 100644 Assets/Scripts/ServerShared/RuntimeGeometry.cs create mode 100644 Assets/Scripts/ServerShared/RuntimeGeometry.cs.meta diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 0c2e822864b4a0b9106a2900cfe779aef5bbca96..21d152db9b70e438cf1ef1bd568bc45e14fbed97 100644 GIT binary patch delta 1697 zcma)7O>Z1U5T#>d9LOaJkPkqVWE2zRU3)i)6R-&}wu1vi1b={VeCh3}-EBP6J?ZYT zS%fgiLP7)!&>rRlQiMq)gp}m8xdw4VNO0h=fZ#8{i6d0+%sM6!2x$+qJ=0aM-g{NG zezotf>wVWQ@7Q^4um_sD=gt27DCrs?9Y!!U{}R+C8g4|r0joT{ILi*M6=AN< zV;q7RZh}}#<)*mfL%>x4=g?HOiMSFt=eUDNuV4W5iH6xkIT_(|s3UZyQ51Fz&QO-@ z^7Ms7#xbvic0(zdX7M&fQ6Gq0)7QYZ7mr?tj9AZ{{l?!Kq8>ASk&ELxh*DS-is*n_Gpm>CqBBFu-ErG8{RinhXA~gXM3DpAg1_@0_K)~w62}4= z&$!&(`sfI|+&|Gib}#`;Rag z2NcM2b*Cb&U&q;Ami{)*`qn-*H5go~bb&8b-dd{MIb}M>lhgu9w0-z=j=S@x^Jn`A zay+~C&mokZb%&4dmZi#IK5CZoQ3C}6^#qYPxVbDK#R7`T^!u+-@uKizD;c^y!z`KzjE{_V}J`xR0DDFK#+sBZm*Po;k_BW4o{Aomc3x z-r9AFz4k)BGU!6{`+kMhWoe0lVxAAHDkzCp^R<{v%#()}Ck-R_5_ R&X#H2*kCtzZk-)p{2T4EUxWYv delta 1319 zcmah}J7^R^7B`T31qMWfXR&%@m-Hq9uS>|!^szU-Q z_(D$I#?BY0pjM|AiiNedL0cOeu@f8pXCI_OM6Vrgn( zw6JG#eEtSm*M8S^Ij@w8u5$Yt>22F?lT{~o?Mn9b^=$3BII}d=(;4a^FSfL%%2pU2 z0ra~@Kk15rprWt`xE7EV$1!!to#a#-tw8{gjJthPwYM814wlU$; zkP9wq)JPdnrVS{`u^$4X3-pxWrb!nSH=t=bwu5BqtkrJ&K^$-tnmdkI?hoyyrVbev z%AzRXI3vQTpc>eiLQ2rMfl>qrQ!$|f=FXLYPZe8CG0z^RRStoV*mV5$5ZTZw-1h>; z!{s}3I3p)Mq7C*YEh7r5pg5%o>c~t&Qe_TgXH=vWK2y!YLjyu{DVD#?aKVD#K&cii(shYqYr}(p!nsIl zz#ool1XIquIhk5BmpJ3po%IuY;#-4ceG3KdTFan7NdKe>PC^WdAC}--}^M?sJT2$20UP*C6J^prq475JaSYs7nZfXk0 zN`c?BMo`GoqLsPtepIvOZ?B)_{k+QTPPf35$fVeg?9k&T{xm6@OYJbSp6&Ly3V7{neF7>>NQVtBU89* zI?syaL0^1)KiS-V|9v5TwT}$7D?ga~^EfV_BLi`Cfb3YCJxjZb^Y;v^A<=E|`730g z^ZEdJNjjIN$?2p0zxT91bZ_cQSCeDyZ`~W>ZCA;g{K*Q* diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index 43288893b..45a6c2e4d 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -130,9 +130,11 @@ hardpoint type, shape fit, hull type, and behavior kind, then instantiates generated equipment directly from typed runtime rows. The surviving trade menu also applies typed catalog prefilters for row size, hardpoint type, and behavior kind before legacy buy actions. -Surviving item catalog Unity DTOs keep local legacy GUID fields only where old -simulation APIs still accept DTO objects. The old `RuntimeCatalogEntry` and -`RuntimeItemProjectionEntry` base names no longer appear in live source. +The old `ItemData`/`EquippableItemData`/`HullData`/`WeaponItemData` DTO +hierarchy has been deleted from live Unity source. Shared runtime geometry and +stat primitives now live in `RuntimeGeometry.cs`; item facts come from typed +runtime rows. The old `RuntimeCatalogEntry` and `RuntimeItemProjectionEntry` +base names no longer appear in live source. The dead `InspectableRuntimeCatalogLinkAttribute` inspector metadata is gone; live Unity source no longer carries `LegacyPayloadKeyAttribute` either. Catalog import and migration readers own deterministic legacy field layout diff --git a/Assets/Scripts/ServerShared/ItemData.cs b/Assets/Scripts/ServerShared/ItemData.cs deleted file mode 100644 index b3b7717ca..000000000 --- a/Assets/Scripts/ServerShared/ItemData.cs +++ /dev/null @@ -1,600 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Unity.Mathematics; -using static Unity.Mathematics.math; -using float2 = Unity.Mathematics.float2; -using int2 = Unity.Mathematics.int2; - -[Inspectable] -public class Shape -{ - public bool[,] Cells; - - private bool _dirty = true; - - public Shape() - { - Cells = new bool[1,1]; - Cells[0, 0] = true; - } - - public Shape(int width, int height) - { - Cells = new bool[width, height]; - } - - public int Width - { - get { return Cells.GetLength(0); } - set { Resize(value, Height); } - } - - public int Height - { - get { return Cells.GetLength(1); } - set { Resize(Width, value); } - } - - public void Resize(int width, int height) - { - var newCells = new bool[width, height]; - - for (int x = 0; x < width; x++) - { - for (int y = 0; y < height; y++) - { - newCells[x, y] = x >= Width || y >= Height || Cells[x, y]; - } - } - - Cells = newCells; - } - - private static int mod(int x, int m) { - int r = x%m; - return r<0 ? r+m : r; - } - - public int2 Rotate(int2 position, ItemRotation rotation) - { - return rotation switch - { - ItemRotation.Clockwise => int2(position.y, Width - 1 - position.x), - ItemRotation.Reversed => int2(Width - 1 - position.x, Height - 1 - position.y), - ItemRotation.CounterClockwise => int2(Height - 1 - position.y, position.x), - _ => int2(position.x, position.y) - }; - } - - private int2[] _cachedShapeCoordinates; - - public int2[] Coordinates - { - get - { - if (_dirty) - { - _cachedShapeCoordinates = EnumerateShapeCoordinates().ToArray(); - _dirty = false; - } - return _cachedShapeCoordinates; - } - } - - private IEnumerable EnumerateShapeCoordinates() - { - for (int y = 0; y < Height; y++) - { - for(int x = 0; x < Width; x++) - { - if(Cells[x,y]) yield return int2(x, y); - } - } - } - - private int2[] _cachedAllShapeCoordinates; - - public int2[] AllCoordinates => _cachedAllShapeCoordinates ?? (_cachedAllShapeCoordinates = EnumerateAllShapeCoordinates().ToArray()); - - private IEnumerable EnumerateAllShapeCoordinates() - { - for (int y = 0; y < Height; y++) - { - for(int x = 0; x < Width; x++) - { - yield return int2(x, y); - } - } - } - - private float2? _centerOfMass; - - public float2 CenterOfMass => _centerOfMass ?? (_centerOfMass = Coordinates - .Aggregate(float2.zero, (total, coord) => total + coord) / Coordinates.Length).Value; - - public bool this[int2 pos] { - get { return pos.x >= 0 && pos.y >= 0 && pos.x < Width && pos.y < Height && Cells[pos.x, pos.y]; } - set - { - if (pos.x < 0 || pos.y < 0 || pos.x >= Width || pos.y >= Height) return; - _dirty = true; - Cells[pos.x, pos.y] = value; - } - } - - public Shape Shrink() - { - var shape = new Shape(Width, Height); - foreach(var shapeCoord in Coordinates) - shape[shapeCoord] = ( - this[shapeCoord + int2(-1,-1)] && this[shapeCoord + int2(0,-1)] && this[shapeCoord + int2(1,-1)] && - this[shapeCoord + int2(-1,0)] && this[shapeCoord + int2(1,0)] && - this[shapeCoord + int2(-1,1)] && this[shapeCoord + int2(0,1)] && this[shapeCoord + int2(1,1)] - ); - return shape; - } - - public Shape Inset(Shape inset, int2 insetPosition, ItemRotation rotation = ItemRotation.None) - { - var shape = new Shape(max(Width,insetPosition.x + inset.Width - 1), max(Height, insetPosition.y + inset.Height - 1)); - foreach (var v in inset.Coordinates) - { - var insetCoord = inset.Rotate(v, rotation) + insetPosition; - shape[insetCoord] = true; - } - - return shape; - } - - public Shape Expand() - { - var shape = new Shape(Width, Height); - foreach (var shapeCoord in AllCoordinates) - shape[shapeCoord] = ( - this[shapeCoord + int2(-1,-1)] || this[shapeCoord + int2(0,-1)] || this[shapeCoord + int2(1,-1)] || - this[shapeCoord + int2(-1,0)] || this[shapeCoord] || this[shapeCoord + int2(1,0)] || - this[shapeCoord + int2(-1,1)] || this[shapeCoord + int2(0,1)] || this[shapeCoord + int2(1,1)] - ); - return shape; - } - - // TODO: Use the power of math to optimize this function! - // Try to find a rotation and position with which a shape can be placed to fit within another shape - public bool FitsWithin(Shape other, out ItemRotation rotation, out int2 position) - { - // Try every item orientation - foreach(var rot in (ItemRotation[])Enum.GetValues(typeof(ItemRotation))) - { - rotation = rot; - if (FitsWithin(other, rot, out var pos)) - { - position = pos; - return true; - } - } - - rotation = ItemRotation.None; - position = int2.zero; - return false; - } - - // Try to find a position with which a shape can be placed to fit within another shape - public bool FitsWithin(Shape other, ItemRotation rotation, out int2 position) - { - var width = rotation == ItemRotation.Clockwise || rotation == ItemRotation.CounterClockwise ? Height : Width; - var height = rotation == ItemRotation.Clockwise || rotation == ItemRotation.CounterClockwise ? Width : Height; - // Try every item position that could possibly fit - for(int x = 0; x < other.Width - width + 1; x++) - { - for (int y = 0; y < other.Height - height + 1; y++) - { - position = int2(x, y); - var fits = true; - foreach (var v in Coordinates) - { - fits = fits && other[Rotate(v, rotation) + position]; - if (!fits) break; - } - - if (fits) return true; - } - } - - position = int2.zero; - return false; - } - - // Set every cell on the line from a to b to true according to Bresenham's Line Algorithm - public void SetLine(float2 a, float2 b) - { - if (a.Equals(b)) - { - return; - } - - // If line gradient is steep, swap x and y - bool steep = Math.Abs(b.y - a.y) > Math.Abs(b.x - a.x); - if (steep) - { - a = new float2(a.y, a.x); - b = new float2(b.y, b.x); - } - - // If b is closer to the origin than a, swap a and b. - if (a.x > b.x) - { - var temp = a; - a = b; - b = temp; - } - - float dx = b.x - a.x; - float dy = b.y - a.y; - float derr = Math.Abs(dy / dx); // dx != 0 - - int y = (int) Math.Round(a.y); - int xStart = (int) Math.Round(a.x); - float error = (a.y - y) + (xStart - a.x) * derr; - - for (int x = xStart; x <= (int) Math.Round(b.x); x++) - { - if (x >= 0 && x < Width && y >= 0 && y < Height) - { - Cells[steep ? y : x, steep ? x : y] = true; - } - error += derr; - if (error >= 0.5f) - { - y += Math.Sign(dy); - error -= 1f; - } - } - - } - -} - -public abstract class ItemData : INamedEntry -{ - public Guid ID = Guid.NewGuid(); - - [Inspectable] - public string Name; - - [InspectableText] - public string Description; - public Guid Manufacturer; - - [Inspectable] - public float Mass; - - [InspectableSchematicShape] - public Shape Shape; - - // Heat needed to change temperature of 1 gram by 1 degree - [Inspectable] - public float SpecificHeat = 1; - - [Inspectable] - public float Conductivity = 1; - - [Inspectable] - public int Price = 0; - - public string EntryName - { - get => Name; - set => Name = value; - } - - public override int GetHashCode() - { - return ID.GetHashCode(); - } - - public override bool Equals(object obj) - { - return obj is ItemData item && item.ID == ID; - } - -} - -[Inspectable] -public class SimpleCommodityData : ItemData -{ - // // Types of body where this resource can be found - // [InspectableField] - // public BodyType ResourceBodyType; - // - // // Controls the lowest value in the resource distribution curve - // [InspectableField] - // public ExponentialLerp Distribution; - // - // // Minimum amount of resources needed for presence to register - // [InspectableField] - // public float Floor = 5f; - - [Inspectable] - public int MaxStack = 10; - - [Inspectable] - public SimpleCommodityCategory Category; -} - -public abstract class CraftedItemData : ItemData -{ - // [Inspectable] - // public float IngredientQualityWeight = .5f; -} - -[Inspectable] -public class CompoundCommodityData : CraftedItemData -{ - public Dictionary DemandProfile = new Dictionary(); - - [Inspectable] - public CompoundCommodityCategory Category; -} - -[Inspectable] -public class ConsumableItemData : CraftedItemData -{ - [Inspectable] - public bool Stackable; - - [Inspectable] - public float Duration; - - [InspectableTexture] - public string Icon; - - [Inspectable] - public BezierCurve Effectiveness; -} - -public abstract class EquippableItemData : CraftedItemData -{ - [InspectableTexture] - public string Schematic; - - [Inspectable] - public float Durability; - - [InspectableTemperature] - public float MinimumTemperature; - - [InspectableTemperature] - public float MaximumTemperature; - - // [InspectableField, SimplePerformanceStat] - // public PerformanceStat DurabilityExponent = new PerformanceStat(); - // - // [InspectableField, SimplePerformanceStat] - // public PerformanceStat HeatExponent = new PerformanceStat(); - - [InspectableAnimationCurve] - public BezierCurve HeatPerformanceCurve; - - [Inspectable] - public float ThermalResilience = 1; - - [InspectableTexture] - public string ActionBarIcon; - - [InspectableSoundBank] - public uint SoundBank; - - [Inspectable] - public List AudioStats = new List(); - - public abstract HardpointType HardpointType { get; } - - private const int STEPS = 64; - - private float? _optimum; - - public float OptimalTemperature - { - get - { - if (_optimum==null) - { - var samples = Enumerable.Range(0, STEPS).Select(i => (float) i / STEPS).ToArray(); - float max = 0; - _optimum = 0; - foreach (var f in samples) - { - var p = HeatPerformanceCurve?.Evaluate(f)??0; - if (p > max) - { - max = p; - _optimum = f; - } - } - } - - return (float) (MinimumTemperature + _optimum * (MaximumTemperature - MinimumTemperature)); - } - } - - public float Performance(float temperature) - { - return saturate(HeatPerformanceCurve?.Evaluate(unlerp(MinimumTemperature, MaximumTemperature, temperature))??1); - } -} - -[Inspectable] -public class AudioStat -{ - [InspectableAudioParameter] - public uint Parameter; - - [Inspectable] - public PerformanceStat Stat = new PerformanceStat(); -} - -[Inspectable] -public class GearData : EquippableItemData -{ - [Inspectable] - public HardpointType Hardpoint; - - public override HardpointType HardpointType => Hardpoint; -} - -[Inspectable] -public class CargoBayData : EquippableItemData -{ - [Inspectable] - public Shape InteriorShape; - - public override HardpointType HardpointType => HardpointType.Tool; -} - -[Inspectable] -public class DockingBayData : CargoBayData -{ - [Inspectable] - public int2 MaxSize; -} - - -public class WeaponItemData : GearData -{ - [Inspectable] - public WeaponRange WeaponRange; - - [Inspectable] - public WeaponCaliber WeaponCaliber; - - [Inspectable] - public WeaponType WeaponType; - - [Inspectable] - public WeaponFireType WeaponFireTypes; - - [Inspectable] - public WeaponModifiers WeaponModifiers; -} - -[Inspectable] -public class HullData : EquippableItemData -{ - [Inspectable] - public List Hardpoints = new List(); - - [InspectablePrefab] - public string Prefab; - - [Inspectable] - public HullType HullType; - - [Inspectable] - public float GridOffset; - - [Inspectable] - public float Armor; - - [Inspectable] - public float Drag; - - [Inspectable] - public bool CanTow; - - public Shape InteriorCells - { - get - { - if (_interiorCells == null) - { - _interiorCells = Shape.Shrink(); - } - - return _interiorCells; - } - } - - private Shape _interiorCells; - - public override HardpointType HardpointType => HardpointType.Hull; -} - -[Inspectable] -public class HardpointData : ITintInspector -{ - [Inspectable] public HardpointType Type; - [Inspectable] public int2 Position; - [Inspectable] public Shape Shape = new Shape(); - [Inspectable] public string Transform; - [Inspectable] public ItemRotation Rotation; - [Inspectable] public float Armor; - - public override string ToString() - { - return $"{Enum.GetName(typeof(HardpointType), Type)} Hardpoint {Rotation.Arrow()}"; - } - - public float3 TintColor - { - get - { - return GetColor(Type); - } - } - - public static float3 GetColor(HardpointType type) - { - if (_tintColors == null) - { - var hardpointTypes = (HardpointType[]) Enum.GetValues(typeof(HardpointType)); - _tintColors = hardpointTypes.ToDictionary(x => x, - x => ColorMath.HsvToRgb(float3(frac((float)(int)x/hardpointTypes.Length + .25f), 1, 1))); - } - - return _tintColors.TryGetValue(type, out var color) ? color : _tintColors[HardpointType.Hull]; - } - - private static Dictionary _tintColors; -} - -public class PerformanceStat -{ - public float Min; - - public float Max; - public float HeatExponentMultiplier; - public float DurabilityExponentMultiplier; - public float QualityExponent; - - private Dictionary> _scaleModifiers; - private Dictionary> _constantModifiers; - - private Dictionary> ScaleModifiers => - _scaleModifiers = _scaleModifiers ?? new Dictionary>(); - - private Dictionary> ConstantModifiers => - _constantModifiers = _constantModifiers ?? new Dictionary>(); - - public Dictionary GetScaleModifiers(Entity entity) - { - if(!ScaleModifiers.ContainsKey(entity)) - ScaleModifiers[entity] = new Dictionary(); - - return ScaleModifiers[entity]; - } - - public Dictionary GetConstantModifiers(Entity entity) - { - if(!ConstantModifiers.ContainsKey(entity)) - ConstantModifiers[entity] = new Dictionary(); - - return ConstantModifiers[entity]; - } -} - diff --git a/Assets/Scripts/ServerShared/ItemData.cs.meta b/Assets/Scripts/ServerShared/ItemData.cs.meta deleted file mode 100644 index 7e35408b7..000000000 --- a/Assets/Scripts/ServerShared/ItemData.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 25f318aff9c2426dbbfda22cb37e63b2 -timeCreated: 1584282670 \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/RuntimeGeometry.cs b/Assets/Scripts/ServerShared/RuntimeGeometry.cs new file mode 100644 index 000000000..2f0eff1d3 --- /dev/null +++ b/Assets/Scripts/ServerShared/RuntimeGeometry.cs @@ -0,0 +1,328 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Mathematics; +using static Unity.Mathematics.math; +using float2 = Unity.Mathematics.float2; +using int2 = Unity.Mathematics.int2; + +[Inspectable] +public class Shape +{ + public bool[,] Cells; + + private bool _dirty = true; + + public Shape() + { + Cells = new bool[1, 1]; + Cells[0, 0] = true; + } + + public Shape(int width, int height) + { + Cells = new bool[width, height]; + } + + public int Width + { + get { return Cells.GetLength(0); } + set { Resize(value, Height); } + } + + public int Height + { + get { return Cells.GetLength(1); } + set { Resize(Width, value); } + } + + public void Resize(int width, int height) + { + var newCells = new bool[width, height]; + + for (var x = 0; x < width; x++) + { + for (var y = 0; y < height; y++) + { + newCells[x, y] = x >= Width || y >= Height || Cells[x, y]; + } + } + + Cells = newCells; + } + + public int2 Rotate(int2 position, ItemRotation rotation) + { + return rotation switch + { + ItemRotation.Clockwise => int2(position.y, Width - 1 - position.x), + ItemRotation.Reversed => int2(Width - 1 - position.x, Height - 1 - position.y), + ItemRotation.CounterClockwise => int2(Height - 1 - position.y, position.x), + _ => int2(position.x, position.y) + }; + } + + private int2[] _cachedShapeCoordinates; + + public int2[] Coordinates + { + get + { + if (_dirty) + { + _cachedShapeCoordinates = EnumerateShapeCoordinates().ToArray(); + _dirty = false; + } + + return _cachedShapeCoordinates; + } + } + + private IEnumerable EnumerateShapeCoordinates() + { + for (var y = 0; y < Height; y++) + { + for (var x = 0; x < Width; x++) + { + if (Cells[x, y]) + yield return int2(x, y); + } + } + } + + private int2[] _cachedAllShapeCoordinates; + + public int2[] AllCoordinates => _cachedAllShapeCoordinates ??= EnumerateAllShapeCoordinates().ToArray(); + + private IEnumerable EnumerateAllShapeCoordinates() + { + for (var y = 0; y < Height; y++) + { + for (var x = 0; x < Width; x++) + { + yield return int2(x, y); + } + } + } + + private float2? _centerOfMass; + + public float2 CenterOfMass => _centerOfMass ??= Coordinates + .Aggregate(float2.zero, (total, coord) => total + coord) / Coordinates.Length; + + public bool this[int2 pos] + { + get { return pos.x >= 0 && pos.y >= 0 && pos.x < Width && pos.y < Height && Cells[pos.x, pos.y]; } + set + { + if (pos.x < 0 || pos.y < 0 || pos.x >= Width || pos.y >= Height) + return; + + _dirty = true; + Cells[pos.x, pos.y] = value; + } + } + + public Shape Shrink() + { + var shape = new Shape(Width, Height); + foreach (var shapeCoord in Coordinates) + { + shape[shapeCoord] = ( + this[shapeCoord + int2(-1, -1)] && this[shapeCoord + int2(0, -1)] && this[shapeCoord + int2(1, -1)] && + this[shapeCoord + int2(-1, 0)] && this[shapeCoord + int2(1, 0)] && + this[shapeCoord + int2(-1, 1)] && this[shapeCoord + int2(0, 1)] && this[shapeCoord + int2(1, 1)] + ); + } + + return shape; + } + + public Shape Inset(Shape inset, int2 insetPosition, ItemRotation rotation = ItemRotation.None) + { + var shape = new Shape(max(Width, insetPosition.x + inset.Width - 1), max(Height, insetPosition.y + inset.Height - 1)); + foreach (var v in inset.Coordinates) + { + var insetCoord = inset.Rotate(v, rotation) + insetPosition; + shape[insetCoord] = true; + } + + return shape; + } + + public Shape Expand() + { + var shape = new Shape(Width, Height); + foreach (var shapeCoord in AllCoordinates) + { + shape[shapeCoord] = ( + this[shapeCoord + int2(-1, -1)] || this[shapeCoord + int2(0, -1)] || this[shapeCoord + int2(1, -1)] || + this[shapeCoord + int2(-1, 0)] || this[shapeCoord] || this[shapeCoord + int2(1, 0)] || + this[shapeCoord + int2(-1, 1)] || this[shapeCoord + int2(0, 1)] || this[shapeCoord + int2(1, 1)] + ); + } + + return shape; + } + + public bool FitsWithin(Shape other, out ItemRotation rotation, out int2 position) + { + foreach (var rot in (ItemRotation[])Enum.GetValues(typeof(ItemRotation))) + { + rotation = rot; + if (FitsWithin(other, rot, out var pos)) + { + position = pos; + return true; + } + } + + rotation = ItemRotation.None; + position = int2.zero; + return false; + } + + public bool FitsWithin(Shape other, ItemRotation rotation, out int2 position) + { + var width = rotation == ItemRotation.Clockwise || rotation == ItemRotation.CounterClockwise ? Height : Width; + var height = rotation == ItemRotation.Clockwise || rotation == ItemRotation.CounterClockwise ? Width : Height; + + for (var x = 0; x < other.Width - width + 1; x++) + { + for (var y = 0; y < other.Height - height + 1; y++) + { + position = int2(x, y); + var fits = true; + foreach (var v in Coordinates) + { + fits = fits && other[Rotate(v, rotation) + position]; + if (!fits) + break; + } + + if (fits) + return true; + } + } + + position = int2.zero; + return false; + } + + public void SetLine(float2 a, float2 b) + { + if (a.Equals(b)) + return; + + var steep = Math.Abs(b.y - a.y) > Math.Abs(b.x - a.x); + if (steep) + { + a = new float2(a.y, a.x); + b = new float2(b.y, b.x); + } + + if (a.x > b.x) + { + var temp = a; + a = b; + b = temp; + } + + var dx = b.x - a.x; + var dy = b.y - a.y; + var derr = Math.Abs(dy / dx); + + var y = (int)Math.Round(a.y); + var xStart = (int)Math.Round(a.x); + var error = (a.y - y) + (xStart - a.x) * derr; + + for (var x = xStart; x <= (int)Math.Round(b.x); x++) + { + if (x >= 0 && x < Width && y >= 0 && y < Height) + { + Cells[steep ? y : x, steep ? x : y] = true; + } + + error += derr; + if (error >= 0.5f) + { + y += Math.Sign(dy); + error -= 1f; + } + } + } +} + +[Inspectable] +public class HardpointData : ITintInspector +{ + [Inspectable] public HardpointType Type; + [Inspectable] public int2 Position; + [Inspectable] public Shape Shape = new Shape(); + [Inspectable] public string Transform; + [Inspectable] public ItemRotation Rotation; + [Inspectable] public float Armor; + + public override string ToString() + { + return $"{Enum.GetName(typeof(HardpointType), Type)} Hardpoint {Rotation.Arrow()}"; + } + + public float3 TintColor + { + get { return GetColor(Type); } + } + + public static float3 GetColor(HardpointType type) + { + if (_tintColors == null) + { + var hardpointTypes = (HardpointType[])Enum.GetValues(typeof(HardpointType)); + _tintColors = hardpointTypes.ToDictionary( + x => x, + x => ColorMath.HsvToRgb(float3(frac((float)(int)x / hardpointTypes.Length + .25f), 1, 1))); + } + + return _tintColors.TryGetValue(type, out var color) ? color : _tintColors[HardpointType.Hull]; + } + + private static Dictionary _tintColors; +} + +public class PerformanceStat +{ + public float Min; + public float Max; + public float HeatExponentMultiplier; + public float DurabilityExponentMultiplier; + public float QualityExponent; + + private Dictionary> _scaleModifiers; + private Dictionary> _constantModifiers; + + private Dictionary> ScaleModifiers => + _scaleModifiers ??= new Dictionary>(); + + private Dictionary> ConstantModifiers => + _constantModifiers ??= new Dictionary>(); + + public Dictionary GetScaleModifiers(Entity entity) + { + if (!ScaleModifiers.ContainsKey(entity)) + ScaleModifiers[entity] = new Dictionary(); + + return ScaleModifiers[entity]; + } + + public Dictionary GetConstantModifiers(Entity entity) + { + if (!ConstantModifiers.ContainsKey(entity)) + ConstantModifiers[entity] = new Dictionary(); + + return ConstantModifiers[entity]; + } +} diff --git a/Assets/Scripts/ServerShared/RuntimeGeometry.cs.meta b/Assets/Scripts/ServerShared/RuntimeGeometry.cs.meta new file mode 100644 index 000000000..40326c812 --- /dev/null +++ b/Assets/Scripts/ServerShared/RuntimeGeometry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49b6dbff1ee0467e98507f18bf7e9ea3 +timeCreated: 1781541660 diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index d8993b3ae..54b7f5295 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -52,9 +52,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. the provider-owned Eve command bridge on startup and on a daemon polling loop while hosting the CultMesh state node. `Aetheria.State.ApplyPending` remains a bounded local operator applicator for both pending lanes. -- Shared item domain state is still partly built around `AetheriaRuntimeItemReference`, - `ItemData`, `RuntimeBehaviorConfig`, derived GUID compatibility in broader - simulation paths, and runtime catalog metadata. Dead +- Shared item domain state is now built around typed item-key references, + typed runtime catalog rows, explicit `RuntimeBehaviorConfig` projection, and + runtime geometry/stat primitives. The old `ItemData` DTO hierarchy is deleted + from live Unity source. Dead user-record and galaxy-map-layer catalog roots have been deleted, and surviving runtime DTOs no longer carry legacy catalog group/table annotations. Newtonsoft, JsonKnownTypes, RethinkDB, LiteNetLib client transport, and the broken @@ -608,9 +609,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. zone for future typed catalog boot. `ActionGameManager` opens the package-owned typed runtime catalog snapshot and binds item reference resolution through `AetheriaRuntimeItemCatalog`. - Runtime code receives narrow `ItemManager` projection methods where gameplay - still needs old `ItemData` DTOs. `Galaxy`, entity restore, and faction-distance - loadout weighting have been moved off legacy faction catalog reads. + Runtime code receives narrow `ItemManager` projection methods over typed + runtime catalog rows and no longer hydrates old `ItemData` DTOs. `Galaxy`, + entity restore, and faction-distance loadout weighting have been moved off + legacy faction catalog reads. The embedded Unity state package owns the read-only runtime catalog model contract and the read-only known-schema `.cc` catalog opener. `ActionGameManager` now exposes that typed package snapshot at boot. The SDK-style @@ -692,9 +694,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. DTO projection caches. - Shared paths: manual gameplay edits, editor edits, server updates, file load, file save, and migration all need to converge on one typed commit primitive. -- Deletion line: no new behavior should be added to old `ItemData` DTO - metadata or MessagePack catalog paths except bounded migration readers and the - current typed behavior config bridge. +- Deletion line: no new behavior should recreate old `ItemData` DTO metadata, + whole-item projection caches, or MessagePack catalog paths except bounded + migration readers. ## Target Authority Map @@ -711,10 +713,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. and any compatibility reader. - Shared paths: gameplay input, editor edits, import/deep-load, replication, simulation ticks, and tests all call the same typed state service. -- Deletion line: replace the remaining `ItemData` runtime DTO projection with - native typed item instances and typed behavior factories, then remove old MessagePack - catalog metadata from live Unity source once import-only migration no longer - needs it. +- Deletion line: continue collapsing the temporary typed behavior-config bridge + into native typed behavior factories, then remove old MessagePack catalog + metadata from live Unity source once import-only migration no longer needs it. ## Intended Change @@ -1244,7 +1245,9 @@ First Aetheria surfaces to publish: - Done: move resource scanner targets and mining tool asteroid belts to typed body-key runtime commit fields; raw body ID commit fields are now compatibility-only fallback input. - - Remove runtime dependency on `ItemData` DTOs as item instance owners. + - Done: delete the old `ItemData`/`EquippableItemData`/`HullData`/ + `WeaponItemData` DTO hierarchy from live Unity source; shared runtime + geometry/stat primitives now live in `RuntimeGeometry.cs`. 5. Mesh host - Replace `Economy.Server` RethinkDB and LiteNetLib database authority with a