Removed LaneSpan, may be add later as diffrent movemnet system.

This commit is contained in:
2026-05-17 23:44:03 -04:00
parent 75c93f0c43
commit 8a0347f1a1
16 changed files with 85 additions and 236 deletions

View File

@@ -0,0 +1 @@
uid://b22vip5klbxnq

View File

@@ -0,0 +1 @@
uid://ddnds4ritwn2f

View File

@@ -0,0 +1 @@
uid://8hihhfy6hol

View File

@@ -0,0 +1 @@
uid://dbb3dlqyskwqs

View File

@@ -32,15 +32,13 @@ public partial class ConveyorBeltStraight : Node3D, IProvide<IVoxelGridRegistry>
// Direction.Back,
Width,
PortAccess.BiDirectional),
new BeltTEnd(ConveyorEnd.Start),
new LaneSpan(0, 1));
new BeltTEnd(ConveyorEnd.Start));
ConveyorLogic.EndPort = ConveyorLogic.CreatePort(
new(VoxelTransform, //new(GridTransform3D.FromGodot(Transform.TranslatedLocal(Vector3.Left)),
// Direction.Front,
Width,
PortAccess.BiDirectional),
new BeltTEnd(ConveyorEnd.End),
new LaneSpan(0, 1));
new BeltTEnd(ConveyorEnd.End));
ConveyorLogic.OtherPorts = [
ConveyorLogic.CreatePort(
@@ -48,15 +46,13 @@ public partial class ConveyorBeltStraight : Node3D, IProvide<IVoxelGridRegistry>
// Direction.Right,
1,
PortAccess.In),
new BeltTOffset(ConveyorLogic.Length/2),
LaneSpan.One),
new BeltTOffset(ConveyorLogic.Length/2)),
ConveyorLogic.CreatePort(
new(VoxelTransform.RotateY90CCW(),
// Direction.Left,
1,
PortAccess.In),
new BeltTOffset(ConveyorLogic.Length/2),
LaneSpan.One)
new BeltTOffset(ConveyorLogic.Length/2))
];
}

View File

@@ -39,8 +39,8 @@ public interface IMovementConveyor
IBeltMovement GetMovementPolicy();
// IList<ConveyorSlice> Items { get; }
IOption<IBeltPort> GetPortFacing(IBeltPort slot);
BeltObstacle GetDistanceToNextItem(BeltDirection beltDirection, float itemBeltT, float maxDistToCheck, LaneSpan laneSpan, HashSet<IMovementConveyor>? visted = null);
ConveyorPort CreatePort(BeltPortProfile profile, BeltT beltT, LaneSpan laneSpan);
BeltObstacle GetDistanceToNextItem(BeltDirection beltDirection, float itemBeltT, float maxDistToCheck, HashSet<IMovementConveyor>? visted = null);
ConveyorPort CreatePort(BeltPortProfile profile, BeltT beltT);
}
public interface IBeltMovement
{
@@ -63,7 +63,7 @@ public sealed class IndividualMovement : IBeltMovement
{
var itemRef = enumerator.Current;
float maxMove = conveyor.SpeedMagnitude * delta;
var space = conveyor.GetDistanceToNextItem(conveyor.GetBeltDirection(), itemRef.Position, maxMove, LaneSpan.One);
var space = conveyor.GetDistanceToNextItem(conveyor.GetBeltDirection(), itemRef.Position, maxMove);
// space -= ITEMSIZE;//AcountForSPacing
@@ -85,7 +85,7 @@ public sealed class IndividualMovement : IBeltMovement
{
var facing = conveyor.GetPortFacing(towardStart ? conveyor.StartPort : conveyor.EndPort);
// GD.Print(facing.HasValue(out var slot2),slot2);// , slot2.CanAccept(new TestItem(),LaneSpan.One,0));
if (facing.HasValue(out var slot) && slot.TryInsert(itemRef.Value, LaneSpan.One, 0))
if (facing.HasValue(out var slot) && slot.TryInsert(itemRef.Value, 0))
{
// GD.Print(space is PortBeltObstacle port?port.LaneSpan:itemRef.Value.LaneSpan);
// GD.PrintS(itemRef.Value.LaneSpan,itemRef.Value.LaneSpan);
@@ -211,9 +211,8 @@ public sealed class StrictMovement : IBeltMovement
if (enumerator.MoveNext())
{
lastPos = enumerator.Current.Position;
freeSpace = conveyor.GetDistanceToNextItem(conveyor.GetBeltDirection(),lastPos,maxMove,LaneSpan.One,[]);
freeSpace = conveyor.GetDistanceToNextItem(conveyor.GetBeltDirection(),lastPos,maxMove,[]);
}
var move = MathF.Min(maxMove, freeSpace.Distance);
if (lastPos > conveyor.Length || lastPos < 0)
{
enumerator = !towardStart ? conveyor.EnumerateTowardStart() : conveyor.EnumerateTowardEnd();
@@ -223,7 +222,7 @@ public sealed class StrictMovement : IBeltMovement
{
var facing = conveyor.GetPortFacing(towardStart ? conveyor.StartPort : conveyor.EndPort);
// GD.Print(facing.HasValue(out var slot2),slot2);// , slot2.CanAccept(new TestItem(),LaneSpan.One,0));
if (facing.HasValue(out var slot) && slot.TryInsert(enumerator.Current.Value, LaneSpan.One, 0))
if (facing.HasValue(out var slot) && slot.TryInsert(enumerator.Current.Value, 0))
{
// GD.Print(space is PortBeltObstacle port?port.LaneSpan:itemRef.Value.LaneSpan);
// GD.PrintS(itemRef.Value.LaneSpan,itemRef.Value.LaneSpan);
@@ -251,7 +250,7 @@ public sealed class StrictMovement : IBeltMovement
{
var facing = conveyor.GetPortFacing(towardStart ? conveyor.StartPort : conveyor.EndPort);
// GD.Print(facing.HasValue(out var slot2),slot2);// , slot2.CanAccept(new TestItem(),LaneSpan.One,0));
if (facing.HasValue(out var slot) && slot.TryInsert(enumerator.Current.Value, LaneSpan.One, 0))
if (facing.HasValue(out var slot) && slot.TryInsert(enumerator.Current.Value, 0))
{
// GD.Print(space is PortBeltObstacle port?port.LaneSpan:itemRef.Value.LaneSpan);
// GD.PrintS(itemRef.Value.LaneSpan,itemRef.Value.LaneSpan);
@@ -268,31 +267,7 @@ public struct ConveyorSlice(IBeltItem item, float beltT = 0)
{
public IBeltItem Item = item;
public float BeltT = beltT;
public LaneSpan LaneSpan = LaneSpan.One;
public override string ToString() => $"{Item}, {BeltT}, {LaneSpan}";
}
public readonly struct LaneSpan : IEquatable<LaneSpan>
{
public readonly ushort Start;
public readonly ushort End;
public readonly int Width => End - Start;
public static readonly LaneSpan One = new(0, 1);
public static readonly LaneSpan Zero = new(0, 0);
public LaneSpan(ushort start, ushort end)
{
Start = start;
End = end;
}
// [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool OverLaps(LaneSpan a, LaneSpan b) => a.Start < b.End && b.Start < a.End;
// [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static LaneSpan Shifted(LaneSpan a, int amount) => checked(new LaneSpan((ushort)(a.Start + amount), (ushort)(a.End + amount)));
public static bool Encapsulates(LaneSpan a, LaneSpan b) => b.Start >= a.Start && b.End <= b.End;
public override string ToString() => $"(Start:{Start}, End:{End})";
public bool Equals(LaneSpan other) => Start == other.Start && End == other.End;
public static bool operator ==(LaneSpan a, LaneSpan b) => a.Equals(b);
public static bool operator !=(LaneSpan a, LaneSpan b) => !a.Equals(b);
public override readonly string ToString() => $"{Item}, {BeltT}";
}
public enum BeltDirection : sbyte

View File

@@ -103,7 +103,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
BeltDirection beltDirection,
float itemBeltT,
float maxDistToCheck,
LaneSpan laneSpan,
HashSet<IMovementConveyor>? visited = null)
{
if (beltDirection == BeltDirection.NotMoving)
@@ -120,11 +119,11 @@ public partial class TestItemConveyor : Node, IMovementConveyor
bool towardStart = beltDirection == BeltDirection.TowardStart;
// 1⃣ Try to find next item on this conveyor
var nextItem = FindNextLocalItem(towardStart, itemBeltT, laneSpan);
var nextItem = FindNextLocalItem(towardStart, itemBeltT);
// GD.Print(nextItem);
if (nextItem.HasValue(out var item))
{
return new ItemBeltObstacle(MathF.Abs(itemBeltT - item.BeltT) - ITEMSIZE, item, laneSpan);
return new ItemBeltObstacle(MathF.Abs(itemBeltT - item.BeltT) - ITEMSIZE, item);
// return MathF.Abs(itemBeltT - item.BeltT);//TODO UseLaneSpan inadditon
}
@@ -133,7 +132,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
towardStart,
itemBeltT,
maxDistToCheck,
laneSpan,
visited
);
@@ -142,8 +140,7 @@ public partial class TestItemConveyor : Node, IMovementConveyor
//ChatGPT Assisted
private IOption<ConveyorSlice> FindNextLocalItem(
bool towardStart,
float itemBeltT,
LaneSpan laneSpan)
float itemBeltT)
{
var sequence = towardStart
? _items.EnumerateTowardStart(itemBeltT)
@@ -168,7 +165,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
bool towardStart,
float itemBeltT,
float maxDistToCheck,
LaneSpan laneSpan,
HashSet<IMovementConveyor> visited)
{
var port = towardStart ? StartPort : EndPort;
@@ -190,13 +186,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
var o = GetPortFacing(port);
if (o.HasValue(out var otherport))
{
var mappedLane2 = MapLaneOrFail(port, otherport, laneSpan);
if (mappedLane2.HasValue(out var lane2))
{
return new PortBeltObstacle(distanceToBoundary, lane2, otherport);
// return new BeltObstacle(ObstacleKind.Boundary,distanceToBoundary+1,lane1,this,null, null);//TODO THIS SHOULD GET SPACE IN PORT SO ITEMS KNOW IF THEY CAN FIT
}
return new BoundaryBeltObstacle(distanceToBoundary);
// return new BeltObstacle(ObstacleKind.Boundary,distanceToBoundary,laneSpan,this,null, null);//TODO THIS SHOULD GET SPACE IN PORT SO ITEMS KNOW IF THEY CAN FIT
}
@@ -208,12 +197,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
return new BoundaryBeltObstacle(distanceToBoundary);
}
var mappedLane = MapLaneOrFail(port, conveyorPort, laneSpan);
if (!mappedLane.HasValue(out var lane))
{
return new BoundaryBeltObstacle(distanceToBoundary);
}
var nextDirection = DirectionAwayFromEnd(end.End);
var startT = end.End == ConveyorEnd.Start
? 0f
@@ -231,7 +214,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
nextDirection,
startT,
maxDistToCheck,
lane,
visited
);
return recursiveDistance with { Distance = recursiveDistance.Distance + distanceToBoundary };
@@ -252,52 +234,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
: None<ConveyorPort>.Of());
}
public IOption<IBeltPort> GetPortFacing(IBeltPort slot) => slot.GetPortFacing(GridRegistry);
private IOption<LaneSpan> MapLaneOrFail(
IBeltPort from,
IBeltPort to,
LaneSpan incoming)
{
// return None<LaneSpan>.Of();
bool mirror = false;
// full mapping of the source port
var mapped = from.MapLaneSpanToFacingPort(to);
if (mapped == LaneSpan.Zero)
return LaneSpan.Zero.ToOption();
int sourceWidth = from.Profile.Width;
int targetWidth = mapped.Width;
int startOffset = incoming.Start; // start relative to source port
int spanLength = incoming.Width;
int newStart;
if (mirror)
{
// mirrored: right side of incoming aligns with right side of mapped
newStart = mapped.End - (startOffset + spanLength);
}
else
{
// normal: left side of incoming aligns with left side of mapped
newStart = mapped.Start + startOffset;
}
int newEnd = newStart + spanLength;
// clamp to mapped range
newStart = Math.Max(mapped.Start, newStart);
newEnd = Math.Min(mapped.End, newEnd);
// GD.Print(incoming, new LaneSpan((ushort)newStart, (ushort)newEnd));
if (newStart >= newEnd)
{
// GD.Print("none");
return None<LaneSpan>.Of();
}
return new LaneSpan((ushort)newStart, (ushort)newEnd).ToOption();
}
private BeltDirection DirectionAwayFromEnd(ConveyorEnd conveyorEnd) => conveyorEnd switch { ConveyorEnd.Start => BeltDirection.TowardEnd, ConveyorEnd.End => BeltDirection.TowardStart, _ => throw new NotSupportedException() };
// public IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardEnd() => Items.EnumerateTowardEnd();
@@ -323,25 +259,25 @@ public partial class TestItemConveyor : Node, IMovementConveyor
// }
// }
public ConveyorPort CreatePort(BeltPortProfile profile, BeltT beltT, LaneSpan laneSpan)
public ConveyorPort CreatePort(BeltPortProfile profile, BeltT beltT)
{
// var towardStartEnd = beltT is ItemConveyor.BeltTEnd end && end.End == ItemConveyor.ConveyorEnd.End;
bool accept(IBeltItem item, float offset, LaneSpan lane)
bool accept(IBeltItem item, float offset)
{
if (beltT is BeltTEnd end)
{
var startBeltT = end.End == ConveyorEnd.Start ? 0 : Length;
var obstacle = GetDistanceToNextItem(end.End.Swap().DirectionTo(), startBeltT, offset, lane);
var obstacle = GetDistanceToNextItem(end.End.Swap().DirectionTo(), startBeltT, offset);
var distanceAllowed = obstacle.Distance;
return ITEMSIZE < distanceAllowed;
}
else if (beltT is BeltTOffset endOffset)
{
return HasClearance(endOffset.T, lane);
return HasClearance(endOffset.T);
}
throw new NotImplementedException();
}
bool tryInsert(IBeltItem item, float offset, LaneSpan laneSpan)
bool tryInsert(IBeltItem item, float offset)
{
if (beltT is BeltTEnd end)
{
@@ -362,7 +298,7 @@ public partial class TestItemConveyor : Node, IMovementConveyor
else if (beltT is BeltTOffset endOffset)
{
if (!HasClearance(endOffset.T, LaneSpan.One))
if (!HasClearance(endOffset.T))
{
return false;
}
@@ -386,20 +322,18 @@ public partial class TestItemConveyor : Node, IMovementConveyor
tryInsert);
return port;
}
private bool HasClearance(float centerT, LaneSpan span)
private bool HasClearance(float centerT)
{
var lower = GetDistanceToNextItem(
BeltDirection.TowardStart,
centerT,
ITEMSIZE,
span
ITEMSIZE
);
var upper = GetDistanceToNextItem(
BeltDirection.TowardEnd,
centerT,
ITEMSIZE,
span
ITEMSIZE
);
float lowerAllowed =
@@ -420,7 +354,7 @@ public partial class TestItemConveyor : Node, IMovementConveyor
}
//TODO Should liklely account for max search distance where the conveyorm may be needed to know
public record class BeltObstacle(float Distance);
public record ItemBeltObstacle(float Distance, ConveyorSlice Item, LaneSpan LaneSpan) : BeltObstacle(Distance);
public record ItemBeltObstacle(float Distance, ConveyorSlice Item) : BeltObstacle(Distance);
public record BoundaryBeltObstacle(float DistanceToBoundary) : BeltObstacle(DistanceToBoundary);
public record PortBeltObstacle(float DistanceToBoundary, LaneSpan LaneSpan, IBeltPort BeltPort) : BoundaryBeltObstacle(DistanceToBoundary);
public record PortBeltObstacle(float DistanceToBoundary, IBeltPort BeltPort) : BoundaryBeltObstacle(DistanceToBoundary);

View File

@@ -40,7 +40,7 @@ public partial class Balancer : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
{
foreach (var portOther in OutputPorts)
{
if (portOther.GetPortFacing(GridRegistry).Map(f => f.CanAccept(item, LaneSpan.One, 0)).Or(false))
if (portOther.GetPortFacing(GridRegistry).Map(f => f.CanAccept(item, 0)).Or(false))
{
return true;
}
@@ -53,7 +53,7 @@ public partial class Balancer : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
for (var i = 0; i < _outPuts.Count; i++)
{
var facing = _outPuts[i].GetPortFacing(GridRegistry);
if (facing.HasValue(out var face) && face.CanAccept(item, LaneSpan.One, 0) && face.TryInsert(item, LaneSpan.One, 0))
if (facing.HasValue(out var face) && face.CanAccept(item, 0) && face.TryInsert(item, 0))
{
var c = _outPuts[i];
_outPuts.RemoveAt(i);

View File

@@ -46,8 +46,8 @@ public partial class BeltPort : Node3D, IBeltPort
base._ExitTree();
}
public bool CanAccept(IBeltItem item, LaneSpan laneSpan, float beltT) => Access.HasFlag(PortAccess.In) && InsertLogic.CanAccept(this, item);
public bool TryInsert(IBeltItem item, LaneSpan laneSpan, float beltT) => CanAccept(item, laneSpan, beltT) && InsertLogic.CanInsert(this, item);
public bool CanAccept(IBeltItem item, float beltT) => Access.HasFlag(PortAccess.In) && InsertLogic.CanAccept(this, item);
public bool TryInsert(IBeltItem item, float beltT) => CanAccept(item, beltT) && InsertLogic.CanInsert(this, item);
}
public interface IBeltItemInsertLogic

View File

@@ -54,11 +54,11 @@ public partial class ItemSpawner : Node3D, IProvide<IBeltPortHost>
}
var itemBlueprint = ItemFactory.GetBlueprint(ItemName);
var dummyItem = new TestItem();
if (beltPort.CanAccept(dummyItem, LaneSpan.One, 0))
if (beltPort.CanAccept(dummyItem, 0))
{
var ctx = new BlueprintContext() { BluePrintId = new BlueprintId(itemBlueprint), World = World };
dummyItem.Item = itemBlueprint.Factory(ctx);
if (!beltPort.TryInsert(dummyItem, LaneSpan.One, 0))
if (!beltPort.TryInsert(dummyItem, 0))
{
World.Destroy(dummyItem.Item);//TODO this should not call, but not sure
GD.PushWarning("Item failed to insert into port and removed item, item was destroyed but make sure item to prevent overhead.");

View File

@@ -95,7 +95,7 @@ public partial class OvenTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
if (_itemBeingHeld.TryGet<Tags>(out var tags) && tags.Contains(TagRegistry.GetTag("cooked")))
{
var port = _insertLogic.GetPorts().FirstOrNone(port => port is BeltPort beltPort && beltPort.PortName == "OutPut").Bind(f => f.GetPortFacing(GridRegistry));
if (port.HasValue(out var v) && _itemBeingHeld.Id != -1 && _itemBeingHeld.IsAlive() && v.TryInsert(new TestItem() { Item = _itemBeingHeld }, LaneSpan.One, 0))
if (port.HasValue(out var v) && _itemBeingHeld.Id != -1 && _itemBeingHeld.IsAlive() && v.TryInsert(new TestItem() { Item = _itemBeingHeld }, 0))
{
_itemBeingHeld = Entity.Null;
}

View File

@@ -63,7 +63,7 @@ public partial class SlicerTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVox
if (sliced.Any())
{
var port = _insertLogic.GetPorts().FirstOrNone(port => port is BeltPort beltPort && beltPort.PortName == "OutPut").Bind(f => f.GetPortFacing(GridRegistry));
if (port.HasValue(out var v) && v.TryInsert(new TestItem() { Item = sliced[0] }, LaneSpan.One, 0))
if (port.HasValue(out var v) && v.TryInsert(new TestItem() { Item = sliced[0] }, 0))
{
GD.Print(sliced[0].Get<Carbohydrates>());
sliced.RemoveAt(0);

View File

@@ -65,7 +65,7 @@ public partial class StackerTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVo
if (_output.Id != -1)
{
var port = _insertLogic.GetPorts().FirstOrNone(port => port is BeltPort beltPort && beltPort.PortName == "OutPut").Bind(f => f.GetPortFacing(GridRegistry));
if (port.HasValue(out var v) && v.TryInsert(new TestItem() { Item = _output }, LaneSpan.One, 0))
if (port.HasValue(out var v) && v.TryInsert(new TestItem() { Item = _output }, 0))
{
_output = Entity.Null;
}

View File

@@ -97,13 +97,11 @@ public interface IBeltPort
bool CanAccept(
IBeltItem item,
LaneSpan laneSpan,
float beltT
);
bool TryInsert(
IBeltItem item,
LaneSpan laneSpan,
float beltT
);
IEnumerable<Vector3I> Points()
@@ -113,22 +111,21 @@ public interface IBeltPort
yield return (Profile.LocalOffset.Right * i) + Profile.LocalOffset.Origin;
}
}
LaneSpan LaneSpan => new(0, (ushort)Profile.Width);
}
public sealed class ConveyorPort : IBeltPort
{
public BeltPortProfile Profile { get; }
public IMovementConveyor Conveyor { get; }
public BeltT BeltT { get; }
private readonly Func<IBeltItem, float, LaneSpan, bool>? _canAccept;
private readonly Func<IBeltItem, float, LaneSpan, bool>? _accept;
private readonly Func<IBeltItem, float, bool>? _canAccept;
private readonly Func<IBeltItem, float, bool>? _accept;
public ConveyorPort(
IMovementConveyor conveyor,
BeltPortProfile profile,
BeltT beltT,
Func<IBeltItem, float, LaneSpan, bool>? canAccept,
Func<IBeltItem, float, LaneSpan, bool>? accept)
Func<IBeltItem, float, bool>? canAccept,
Func<IBeltItem, float, bool>? accept)
{
Conveyor = conveyor;
Profile = profile;
@@ -139,7 +136,6 @@ public sealed class ConveyorPort : IBeltPort
public bool CanAccept(
IBeltItem item,
LaneSpan laneSpan,
float beltT)
{
if (!Profile.Access.HasFlag(PortAccess.In))
@@ -151,28 +147,19 @@ public sealed class ConveyorPort : IBeltPort
{
return false;
}
// LaneSpan checks live here, not in delegates
if (!LaneSpan.Encapsulates(
new LaneSpan(0, (ushort)Profile.Width),
laneSpan))
{
return false;
}
return _canAccept(item, beltT, laneSpan);
return _canAccept(item, beltT);
}
public bool TryInsert(
IBeltItem item,
LaneSpan laneSpan,
float beltT)
{
if (!CanAccept(item, laneSpan, beltT))
if (!CanAccept(item, beltT))
{
return false;
}
return _accept!(item, beltT, laneSpan);
return _accept!(item, beltT);
}
}
[Flags]
@@ -184,88 +171,3 @@ public enum PortAccess : byte
InOut = In | Out,
BiDirectional = InOut
}
public static class SlotExtension
{
public static LaneSpan MapLaneSpanToFacingPort(this IBeltPort self, IBeltPort other) => MapSlotToFacingSlot(self.Profile.LocalOffset, self.Profile.Width, other.Profile.LocalOffset, other.Profile.Width);
public static LaneSpan MapSlotToFacingSlot(
GridTransform3D fromTx,
int fromWidth,
GridTransform3D toTx,
int toWidth)
{
ushort minLane = ushort.MaxValue;
ushort maxLane = ushort.MinValue;
// In port-local space:
// +Z = forward
// +X = width axis
// origin = port center / lane 0 start
// (adjust if your convention differs)
for (int i = 0; i < fromWidth; i++)
{
var fromLocalLane = new Vector3I(i, 0, 0);
var fromLocalFacing = fromLocalLane + Vector3I.Forward;
var worldFacing = fromTx.LocalToWorld(fromLocalFacing);
var toLocal = toTx.WorldToLocal(worldFacing);
int laneIndex = toLocal.X;
bool inWidth = laneIndex >= 0 && laneIndex < toWidth;
bool onFacePlane = toLocal.Z == 0; // directly entering target face
if (!inWidth || !onFacePlane)
continue;
minLane = (ushort)Math.Min(minLane, laneIndex);
maxLane = (ushort)Math.Max(maxLane, laneIndex);
}
if (minLane > maxLane)
return LaneSpan.Zero;
return new LaneSpan(minLane, (ushort)(maxLane + 1));
}
// Map a sub-span from 'from' port into the 'to' port space
public static LaneSpan MapLaneSpan(this IBeltPort from, IBeltPort to, LaneSpan incoming)
{
ushort minLane = ushort.MaxValue;
ushort maxLane = ushort.MinValue;
// Loop over each lane in the incoming span
for (int i = incoming.Start; i < incoming.End; i++)
{
// from-local lane
var fromLocalLane = new Vector3I(i, 0, 0);
// shift forward along +Z to "face" the target
var fromLocalFacing = fromLocalLane + Vector3I.Forward;
// world space
var worldFacing = from.Profile.LocalOffset.LocalToWorld(fromLocalFacing);
// target local space
var toLocal = to.Profile.LocalOffset.WorldToLocal(worldFacing);
int laneIndex = toLocal.X;
bool inWidth = laneIndex >= 0 && laneIndex < to.Profile.Width;
bool onFacePlane = toLocal.Z == 0; // entering target face
if (!inWidth || !onFacePlane)
continue;
minLane = (ushort)Math.Min(minLane, laneIndex);
maxLane = (ushort)Math.Max(maxLane, laneIndex);
}
if (minLane > maxLane)
return LaneSpan.Zero;
return new LaneSpan(minLane, (ushort)(maxLane + 1));
}
}

View File

@@ -1,11 +1,14 @@
namespace FoodFactory;
using System.Collections.Generic;
using System.IO;
using Arch.Core;
using Arch.Core.Extensions;
using Arch.Core.Utils;
using Arch.LowLevel;
using Arch.Persistence;
using Chickensoft.Introspection;
using Chickensoft.SaveFileBuilder;
using FoodFactory.Items;
using FoodFactory.Math;
using Godot;
@@ -61,7 +64,35 @@ public class Test
// GD.Print(worldJson);
var otherWorld = serializer.FromJson(worldJson);
// ISaveChunk<GameData> saveChunk =new SaveChunk<GameData>(
// chunk =>
// {
// var gameData = new GameData()
// {
// World = chunk.GetChunkSaveData<World>()
// };
// return gameData;
// },
// (chunk, data) =>
// {
// chunk.LoadChunkSaveData(data.World);
// }
// );
// ISaveFile<GameData> saveFile = new SaveFile<GameData>(
// saveChunk,
// async data =>
// {
// var json = JsonSerializer.Serialize(data);
// var access = Godot.FileAccess.Open("user://TestSave.jsonc",Godot.FileAccess.ModeFlags.Write);
// access.StoreBuffer(json);
// },
// async () =>
// {
// var access = Godot.FileAccess.Open("user://TestSave.jsonc",Godot.FileAccess.ModeFlags.Read);
// var json = access.GetBuffer((long)access.GetLength());
// return JsonSerializer.Deserialize<GameData>(json);
// }
// );
}
}
public class TagsSerializer : IJsonFormatter<Tags>
@@ -278,3 +309,9 @@ public class BucketStorage<T>
}
[Meta, Id("game_data")]
public partial record GameData
{
public required World World { get; init; }
}