Removed LaneSpan, may be add later as diffrent movemnet system.
This commit is contained in:
1
src/Arch.Extended/Arch.Persistence/Binary.cs.uid
Normal file
1
src/Arch.Extended/Arch.Persistence/Binary.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b22vip5klbxnq
|
||||
1
src/Arch.Extended/Arch.Persistence/Json.cs.uid
Normal file
1
src/Arch.Extended/Arch.Persistence/Json.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddnds4ritwn2f
|
||||
1
src/Arch.Extended/Arch.Persistence/Serializer.cs.uid
Normal file
1
src/Arch.Extended/Arch.Persistence/Serializer.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://8hihhfy6hol
|
||||
@@ -0,0 +1 @@
|
||||
uid://dbb3dlqyskwqs
|
||||
@@ -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))
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user