Changed Namespaces, Move files
This commit is contained in:
@@ -1,61 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using Godot;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Balancer : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxelGridRegistry>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
private BeltPortHost _insertLogic = default!;
|
||||
public IBeltPortHost Value() => _insertLogic;
|
||||
IVoxelGridRegistry IProvide<IVoxelGridRegistry>.Value() => GridRegistry;
|
||||
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn<IVoxelGridRegistry>();
|
||||
private List<BeltPort> _outPuts = new();
|
||||
public GridTransform3D VoxelTransform
|
||||
{
|
||||
get => GridTransform3D.FromGodot(GlobalTransform);
|
||||
set => GlobalTransform = value.ToGodot();
|
||||
}
|
||||
public void OnResolved()
|
||||
{
|
||||
_insertLogic = new BeltPortHost();
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.Access.HasFlag(PortAccess.In), () => new DelegateInsertBeltItemLogic(CanAccept, CanInsert));
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.Access.HasFlag(PortAccess.Out), () => new DelegateInsertBeltItemLogic((_, _) => true, (_, _) => true));
|
||||
this.Provide();
|
||||
_outPuts = [.. OutputPorts];
|
||||
|
||||
}
|
||||
|
||||
private bool CanAccept(IBeltPort port, IBeltItem item)
|
||||
{
|
||||
foreach (var portOther in OutputPorts)
|
||||
{
|
||||
if (portOther.GetPortFacing(GridRegistry).Map(f => f.CanAccept(item, LaneSpan.One, 0)).Or(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private IEnumerable<BeltPort> OutputPorts => _insertLogic.GetPorts().OfType<BeltPort>().Where(i => i.Access.HasFlag(PortAccess.Out));
|
||||
private bool CanInsert(IBeltPort port, IBeltItem item)
|
||||
{
|
||||
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))
|
||||
{
|
||||
var c = _outPuts[i];
|
||||
_outPuts.RemoveAt(i);
|
||||
_outPuts.Add(c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://opbkqoaa7x2n
|
||||
@@ -1,53 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using System;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
[Tool]
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class BeltPort : Node3D, IBeltPort
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Dependency] public IVoxelGridRegistry Grid => this.DependOn<IVoxelGridRegistry>();
|
||||
[Dependency] public IBeltPortHost InsertLogicHost => this.DependOn<IBeltPortHost>();
|
||||
public IBeltItemInsertLogic InsertLogic { get; set; } = default!;
|
||||
[Export] public Direction Face { get; set; } = default!;
|
||||
[Export] public int Width { get; set; } = default!;
|
||||
[Export] public PortAccess Access { get; set; } = default!;
|
||||
[Export] public string PortName { get; set; } = "";
|
||||
[Dependency] public IItemRenderer ItemRenderer => this.DependOn<IItemRenderer>();
|
||||
public BeltPortProfile Profile => new(GridTransform3D.FromGodot(GlobalTransform), Width, Access);
|
||||
private VoxelGuid _guid = new(Guid.Empty);
|
||||
public void OnResolved()
|
||||
{
|
||||
if (Engine.IsEditorHint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
InsertLogic ??= InsertLogicHost.ResolveInsertLogic(this);
|
||||
_guid = Grid.Register<IBeltPort>(this, [.. (this as IBeltPort).Points()]);
|
||||
GD.Print(_guid);
|
||||
}
|
||||
public override void _Process(double delta) => DebugDraw3D.DrawLine(GlobalPosition, GlobalTransform * Face.ToVector(), Colors.Red);
|
||||
public override void _ExitTree()
|
||||
{
|
||||
|
||||
if (Engine.IsEditorHint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Grid.UnRegister(_guid);
|
||||
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 interface IBeltItemInsertLogic
|
||||
{
|
||||
bool CanInsert(IBeltPort beltPort, IBeltItem item);
|
||||
bool CanAccept(IBeltPort beltPort, IBeltItem item);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://ee5aoxi8mjnw
|
||||
@@ -1,48 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public interface IBeltPortHost
|
||||
{
|
||||
IBeltItemInsertLogic ResolveInsertLogic(IBeltPort port);
|
||||
}
|
||||
public class BeltPortHost : IBeltPortHost
|
||||
{
|
||||
private readonly List<(Func<IBeltPort, bool> match, Func<IBeltItemInsertLogic> factory)> _bindings
|
||||
= new();
|
||||
|
||||
public BeltPortHost Bind(
|
||||
Func<IBeltPort, bool> match,
|
||||
Func<IBeltItemInsertLogic> factory)
|
||||
{
|
||||
_bindings.Add((match, factory));
|
||||
return this;
|
||||
}
|
||||
private HashSet<IBeltPort> _ports = [];
|
||||
public IBeltItemInsertLogic? Default;
|
||||
|
||||
/// <summary>
|
||||
/// Resolve the insert logic for a port. If no matching bind exists then the default is returned if supplied. Other wise throws an Exception.
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public IBeltItemInsertLogic ResolveInsertLogic(IBeltPort port)
|
||||
{
|
||||
_ports.Add(port);
|
||||
foreach (var (match, factory) in _bindings)
|
||||
{
|
||||
if (match(port))
|
||||
{
|
||||
return factory();
|
||||
}
|
||||
}
|
||||
if (Default is null)
|
||||
{
|
||||
throw new Exception($"{nameof(port)} does not have any binding attached that accepts it.");
|
||||
}
|
||||
return Default;
|
||||
}
|
||||
public IEnumerable<IBeltPort> GetPorts() => _ports;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://mimkyombngwg
|
||||
@@ -1,116 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ConveyorItemRender : Node
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Export] protected Path3D Path3D { get; set; } = default!;
|
||||
[Export] protected TestItemConveyor ItemConveyor { get; set; } = default!;
|
||||
[Chickensoft.AutoInject.Dependency] protected IItemRenderer Items => this.DependOn<IItemRenderer>();
|
||||
private Chickensoft.Sync.Primitives.AutoList<ConveyorSlice>.Binding _binding = default!;
|
||||
public override async void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
if (!ItemConveyor.IsNodeReady())
|
||||
{
|
||||
await ToSignal(ItemConveyor, Node.SignalName.Ready);
|
||||
}
|
||||
_binding = ItemConveyor.Items.Items.Bind();
|
||||
// binding.OnRemove(callback =>
|
||||
// {
|
||||
// Items.Remove(callback.Item);
|
||||
// // GD.PrintS(callback.Item, callback.BeltT);
|
||||
// // if (itemsRenders.TryGetValue(callback.Item, out var node))
|
||||
// // {
|
||||
// // GD.PrintS(callback.Item, callback.BeltT,node);
|
||||
// // itemsRenders.Remove(callback.Item);
|
||||
// // node.QueueFree();
|
||||
// // }
|
||||
// });
|
||||
_binding.OnAdd((i, v) => Items.UpdateTransform(i.Item, Path3D.GlobalTransform * Path3D.Curve.SampleBakedWithRotation(i.BeltT)));
|
||||
_binding.OnUpdate((a, b) => Items.UpdateTransform(a.Item, Path3D.GlobalTransform * Path3D.Curve.SampleBakedWithRotation(b.BeltT).Translated(-Path3D.Curve.SampleBakedWithRotation(b.BeltT).Basis.X * b.LaneSpan.Start)));
|
||||
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_binding.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IItemRenderer
|
||||
{
|
||||
// Node3D GetVisualNode(IBeltItem beltItem);
|
||||
void UpdateTransform(IBeltItem beltItem, Transform3D newTransform);
|
||||
void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time);
|
||||
void Remove(IBeltItem beltItem);
|
||||
}
|
||||
public partial class ItemRenderSimple : Node3D, IItemRenderer
|
||||
{
|
||||
public Dictionary<IBeltItem, Node3D> _items = [];
|
||||
public void Remove(IBeltItem beltItem)
|
||||
{
|
||||
if (_items.TryGetValue(beltItem, out var node))
|
||||
{
|
||||
node.QueueFree();
|
||||
}
|
||||
_items.Remove(beltItem);
|
||||
}
|
||||
|
||||
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time)
|
||||
{
|
||||
if (!_items.TryGetValue(beltItem, out var node))
|
||||
{
|
||||
_items.Add(beltItem, node = beltItem.CreateItemVisual());
|
||||
AddChild(node);
|
||||
beltItem.Disposed += _ => { node.QueueFree(); _items.Remove(beltItem); };
|
||||
node.Transform = newTransform;
|
||||
return;
|
||||
}
|
||||
node.Transform = newTransform;
|
||||
}
|
||||
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform) => UpdateTransform(beltItem, newTransform, .25f);
|
||||
}
|
||||
public partial class TestItemRendered : Node3D, IItemRenderer
|
||||
{
|
||||
public Dictionary<IBeltItem, Node3D> _items = [];
|
||||
private ConditionalWeakTable<IBeltItem, Tween> _tweens = [];
|
||||
public void Remove(IBeltItem beltItem)
|
||||
{
|
||||
if (_items.TryGetValue(beltItem, out var node))
|
||||
{
|
||||
node.QueueFree();
|
||||
}
|
||||
_items.Remove(beltItem);
|
||||
}
|
||||
|
||||
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time)
|
||||
{
|
||||
if (!_items.TryGetValue(beltItem, out var node))
|
||||
{
|
||||
_items.Add(beltItem, node = beltItem.CreateItemVisual());
|
||||
AddChild(node);
|
||||
beltItem.Disposed += _ => { node.QueueFree(); _items.Remove(beltItem); };
|
||||
node.Transform = newTransform;
|
||||
return;
|
||||
}
|
||||
if (_tweens.TryGetValue(beltItem, out var tween))
|
||||
{
|
||||
tween.Kill();
|
||||
_tweens.Remove(beltItem);
|
||||
}
|
||||
// GD.Print(newTransform);
|
||||
tween = GetTree().CreateTween().BindNode(node);
|
||||
tween.TweenProperty(node, "transform", newTransform, time);
|
||||
_tweens.Add(beltItem, tween);
|
||||
}
|
||||
|
||||
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform) => UpdateTransform(beltItem, newTransform, .25f);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://bjuntmf2sjynp
|
||||
@@ -1,274 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Chickensoft.Sync.Primitives;
|
||||
using SJK.Functional;
|
||||
|
||||
public interface IMovementConveyor
|
||||
{
|
||||
IBeltPort StartPort { get; }
|
||||
// IBeltSlotProfile StartPort { get; }
|
||||
IBeltPort EndPort { get; }
|
||||
// IBeltSlotProfile EndPort { get; }
|
||||
// IOption<IBeltSlotProfile> InputPort { get; }
|
||||
// IOption<IBeltSlotProfile> OutputPort { get; }
|
||||
// IEnumerable<IBeltSlotProfile> GetPorts();
|
||||
IEnumerable<IBeltPort> GetPorts();
|
||||
IAutoValue<float> SpeedValue { get; }
|
||||
float SpeedMagnitude { get; set; }
|
||||
float SignedSpeed { get; set; }
|
||||
bool IsReversed { get; set; }
|
||||
float Length { get; set; }
|
||||
// float GetAvailableTravel(ItemConveyor.BeltDirection beltDirection, LaneSpanT itemSpan, float maxDistance);
|
||||
// IBeltSlotProfile GetPortFacingStart();
|
||||
// IBeltSlotProfile GetPortFacingEnd();
|
||||
BeltDirection GetBeltDirection();
|
||||
// Option<ConveyorSlice> GetItemTowardStart();
|
||||
// Option<ConveyorSlice> GetItemTowardEnd();
|
||||
// Option<ConveyorSlice> GetItemTowardInput();
|
||||
// Option<ConveyorSlice> GetItemTowardOutput();
|
||||
IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardEnd();
|
||||
IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardStart();
|
||||
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);
|
||||
}
|
||||
public readonly struct ConveyorItemHandle
|
||||
{
|
||||
private readonly Action _remove;
|
||||
private readonly Action<ConveyorSlice> _replace;
|
||||
public int Index { get; }
|
||||
public ConveyorSlice Slice { get; }
|
||||
public IBeltItem Item => Slice.Item;
|
||||
public LaneSpan Span => Slice.LaneSpan;
|
||||
public float BeltT => Slice.BeltT;
|
||||
public ConveyorItemHandle(int index, ConveyorSlice slice, Action remove, Action<ConveyorSlice> replace)
|
||||
{
|
||||
Index = index;
|
||||
Slice = slice;
|
||||
_remove = remove;
|
||||
_replace = replace;
|
||||
}
|
||||
public void Remove() => _remove();
|
||||
public void Replace(ConveyorSlice slice) => _replace(slice);
|
||||
}
|
||||
public interface IBeltMovement
|
||||
{
|
||||
void AdvanceBelt(IMovementConveyor conveyor, float delta);
|
||||
|
||||
}
|
||||
public sealed class IndividualMovement : IBeltMovement
|
||||
{
|
||||
public void AdvanceBelt(IMovementConveyor conveyor, float delta)
|
||||
{
|
||||
// GD.Print(conveyor.Items);
|
||||
if (conveyor.GetBeltDirection() == BeltDirection.NotMoving)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// GD.Print("hello");
|
||||
var towardStart = conveyor.GetBeltDirection() == BeltDirection.TowardStart;
|
||||
foreach (var itemRef in towardStart ? conveyor.EnumerateTowardStart() : conveyor.EnumerateTowardEnd())
|
||||
{
|
||||
float maxMove = conveyor.SpeedMagnitude * delta;
|
||||
var space = conveyor.GetDistanceToNextItem(conveyor.GetBeltDirection(), itemRef.Value.BeltT, maxMove, itemRef.Value.LaneSpan);
|
||||
|
||||
|
||||
// space -= ITEMSIZE;//AcountForSPacing
|
||||
// if ()
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (space is ItemBeltObstacle itemOb && itemOb.Distance <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
float amountToMove = Mathf.Min(space.Distance, maxMove);
|
||||
|
||||
itemRef.Replace(itemRef.Value with { BeltT = itemRef.Value.BeltT + amountToMove * Mathf.Sign(conveyor.SignedSpeed) });
|
||||
// GD.PrintS(conveyor.Items.Count,space,amountToMove," "+ itemRef.BeltT,itemRef.Item,conveyor.GetBeltDirection(),towardStart);
|
||||
if (towardStart ? itemRef.Value.BeltT <= 0 : itemRef.Value.BeltT >= conveyor.Length)
|
||||
{
|
||||
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.Item, space is PortBeltObstacle portO ? portO.LaneSpan : itemRef.Value.LaneSpan, 0))
|
||||
{
|
||||
// GD.Print(space is PortBeltObstacle port?port.LaneSpan:itemRef.Value.LaneSpan);
|
||||
// GD.PrintS(itemRef.Value.LaneSpan,itemRef.Value.LaneSpan);
|
||||
// GD.Print(itemRef.Item);
|
||||
itemRef.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public sealed class StrictMovement : IBeltMovement
|
||||
{
|
||||
// // public event IBeltMovement.ItemMoved? OnItemMoved;
|
||||
|
||||
// public void AdvanceBelt(ItemConveyor conveyor, float delta)
|
||||
// {
|
||||
// if (!conveyor.AnyItems())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// var beltDirection = conveyor.GetBeltDirection();
|
||||
// if (beltDirection == BeltDirection.NotMoving)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// var towardStart = beltDirection == BeltDirection.TowardStart;
|
||||
// // GD.Print("Thing: " + Speed + " "+ conveyor.GetConveyorPortFacing(conveyor.GetOutputPort()));
|
||||
// // var moveItemsIntoNextBelt = false;
|
||||
// var next = conveyor.GetConveyorPortFacing(conveyor.GetOutputPort());
|
||||
// var possibleItemTravel = conveyor.GetAvailableTravelForFrontItem(next.HasValue);
|
||||
|
||||
// // return;
|
||||
// if (!possibleItemTravel.HasValue)
|
||||
// {
|
||||
// //There is no items, this should not be called
|
||||
// throw new NotSupportedException("This should not e possible if there is no items or the belt is not moving, it should have returend before");
|
||||
// }
|
||||
// // if (next.HasValue && next.Value.Port.BeltT is BeltTEnd beltTEnd && (next.Value.Port.Direction == PortAccess.In || next.Value.Port.Direction == PortAccess.BiDirectional))
|
||||
// // {
|
||||
// // possibleItemTravel += next.Value.Conveyor.DistanceFromEnd(beltTEnd.End);
|
||||
// // moveItemsIntoNextBelt = true;
|
||||
// // }
|
||||
|
||||
|
||||
// // var itemPair = conveyor.GetFirstItem();
|
||||
// // var distToEnd = conveyor.GetAvailableTravel(conveyor.ItemsCount - 1, beltDirection);//(Speed < 0 ? ConveyorEnd.Start : ConveyorEnd.End);
|
||||
// var maxSpeed = Mathf.Min(conveyor.SpeedMagnitude * delta, possibleItemTravel.Value) * Mathf.Sign(conveyor.SignedSpeed);//Or possibly (int)BeltDirection, givn that they stgore the sign as part of the enum
|
||||
// if (maxSpeed == 0)
|
||||
// {
|
||||
// // var fI = conveyor.GetAvailableTravelForFrontItem();
|
||||
// // if (fI.HasValue && fI.Value <= 0 && next.Value.Port.TryInsertItem(conveyor.GetFirstItem().Value.Item, LaneSpan.One))
|
||||
// // {
|
||||
// // GD.Print("Item Moved");
|
||||
// // conveyor._items.Remove(conveyor.GetFirstItem().Value);
|
||||
// // }
|
||||
|
||||
// return;
|
||||
// }
|
||||
// List<ConveyorSlice> toMove = [];
|
||||
// // Dictionary<IBeltItem, List<ItemMovementSegment>> moves = [];
|
||||
// for (int i = 0; i < conveyor.ItemsCount; i++)
|
||||
// {
|
||||
// // List<ItemMovementSegment> segments = [];
|
||||
// // var startT = conveyor._items[i].BeltT;
|
||||
// var endT = Mathf.Clamp(conveyor._items[i].BeltT + maxSpeed, 0, conveyor.Length);
|
||||
|
||||
// conveyor._items[i] = conveyor._items[i] with { BeltT = endT };
|
||||
// // segments.Add(new(conveyor, startT, towardStart? Mathf.Max(endT, 0) : Mathf.Min(endT, conveyor.Length),Mathf.Abs(maxSpeed)));
|
||||
// if (towardStart ? (endT <= 0) : endT >= conveyor.Length)
|
||||
// {
|
||||
// toMove.Add(conveyor._items[i]);
|
||||
// // segments.Add(new(next.Value.Conveyor, ));
|
||||
// }
|
||||
// // moves.Add(conveyor._items[i].Item, segments);
|
||||
|
||||
// GD.Print($"Item: {conveyor._items[i].Item}, Position:{endT}");
|
||||
// }
|
||||
// // conveyor._items.ForEach((item) => item = item = Mathf.Clamp(item.Position + maxSpeed, 0, Length));
|
||||
// // var list = _items.Where(item=> Speed>=0?item.BeltT >= Length:item.BeltT <= 0).ToList();
|
||||
// // GD.Print(list.Count);
|
||||
// if (next.HasValue)
|
||||
// {
|
||||
// foreach (var item in toMove)
|
||||
// {
|
||||
// GD.Print($"Item: {item.Item}, Position:{item.BeltT} -----------------");
|
||||
// //TEST
|
||||
// // var v = GetConveyorPortFacing(GetOutputPort());
|
||||
// // if (v.HasValue)//Should be true if items are > Length
|
||||
// // {
|
||||
// // GD.PrintS(v.Value.Port.LocalOffset,v.Value.Port.BeltT,v.Value.Port.Direction,v.Value.Port.PullPush,v.Value.Port.Face);
|
||||
// // var end = (next.Value.Port.BeltT as BeltTEnd).End;
|
||||
// // next.Value.Conveyor.InsertAtEndWithoutCheck(end, item.Item);
|
||||
// if (next.Value.Port.TryInsertItem(item.Item, item.LaneSpan))
|
||||
// {
|
||||
// GD.Print("Item Moved");
|
||||
// conveyor._items.Remove(item);
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void AdvanceBelt(IMovementConveyor conveyor, float delta) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 enum BeltDirection : sbyte
|
||||
{
|
||||
TowardStart = -1,
|
||||
NotMoving = 0,
|
||||
TowardEnd = 1
|
||||
}
|
||||
public enum ConveyorEnd { Start, End }
|
||||
|
||||
public abstract record BeltT();
|
||||
public record BeltTEnd(ConveyorEnd End) : BeltT();
|
||||
public record BeltTOffset(float T) : BeltT();
|
||||
|
||||
public static class ConveyorExtensions
|
||||
{
|
||||
|
||||
public static IOption<IBeltPort> GetPortFacing(this IBeltPort slot, IVoxelGridRegistry gridRegistry)
|
||||
{
|
||||
var toCheck = new List<Vector3I>();
|
||||
for (int i = 0; i < slot.Profile.Width; i++)
|
||||
{
|
||||
toCheck.Add(slot.Profile.LocalOffset.LocalToWorld(Vector3I.Forward));
|
||||
}
|
||||
return gridRegistry
|
||||
.Get<IBeltPort>([.. toCheck])
|
||||
.Where(port => port.Profile.LocalOffset.TransformDirection(Vector3I.Forward) == slot.Profile.LocalOffset.TransformDirection(Vector3I.Back))
|
||||
.FirstOrNone();
|
||||
}
|
||||
public static BeltDirection DirectionTo(this ConveyorEnd end) => end switch
|
||||
{
|
||||
ConveyorEnd.Start => BeltDirection.TowardStart,
|
||||
ConveyorEnd.End => BeltDirection.TowardEnd,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
public static ConveyorEnd Swap(this ConveyorEnd end) => end switch { ConveyorEnd.Start => ConveyorEnd.End, ConveyorEnd.End => ConveyorEnd.Start, _ => throw new NotSupportedException() };
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://cx35jfqkjnou8
|
||||
@@ -1,70 +0,0 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace FoodFactory;
|
||||
|
||||
using Arch.Core;
|
||||
using ChickenGameTest;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory.Recipes;
|
||||
using Godot;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ItemSpawner : Node3D, IProvide<IBeltPortHost>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn<IVoxelGridRegistry>();
|
||||
[Dependency] public IBlueprintManger ItemFactory => this.DependOn<IBlueprintManger>();
|
||||
[Dependency] public World World => this.DependOn<World>();
|
||||
[Dependency] public IRecipes Recipes => this.DependOn<IRecipes>();
|
||||
private BeltPortHost _insertLogic = default!;
|
||||
public IBeltPortHost Value() => _insertLogic;
|
||||
private VoxelGuid _guid;
|
||||
public GridTransform3D VoxelTransform
|
||||
{
|
||||
get => GridTransform3D.FromGodot(GlobalTransform);
|
||||
set => GlobalTransform = value.ToGodot();
|
||||
}
|
||||
[Export] public string ItemName { get; set; } = default!;
|
||||
public override void _Ready()
|
||||
{
|
||||
_insertLogic = new BeltPortHost
|
||||
{
|
||||
Default = new DelegateInsertBeltItemLogic((_, _) => false, (_, _) => false)
|
||||
};
|
||||
var timer = new Timer() { Autostart = true, WaitTime = 1f };
|
||||
AddChild(timer);
|
||||
timer.Timeout += Tick;
|
||||
this.Provide();
|
||||
}
|
||||
public void OnResolved() => _guid = GridRegistry.Register(this, VoxelTransform.Origin);
|
||||
|
||||
public override void _ExitTree() => GridRegistry.UnRegister(_guid);
|
||||
public void Tick()
|
||||
{
|
||||
var ports = _insertLogic.GetPorts();
|
||||
foreach (var item in ports)
|
||||
{
|
||||
var port = item.GetPortFacing(GridRegistry);
|
||||
if (!port.HasValue(out var beltPort))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var itemBlueprint = ItemFactory.GetBlueprint(ItemName);
|
||||
var dummyItem = new TestItem();
|
||||
if (beltPort.CanAccept(dummyItem, LaneSpan.One, 0))
|
||||
{
|
||||
var ctx = new BlueprintContext() { BluePrintId = new BlueprintId(itemBlueprint), World = World };
|
||||
dummyItem.Item = itemBlueprint.Factory(ctx);
|
||||
if (!beltPort.TryInsert(dummyItem, LaneSpan.One, 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
uid://btmbv7oaeps4p
|
||||
@@ -1,245 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Arch.Core;
|
||||
using Arch.Core.Extensions;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory;
|
||||
using FoodFactory.Items;
|
||||
using FoodFactory.Recipes;
|
||||
using Godot;
|
||||
using SJK.Functional;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class OvenTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxelGridRegistry>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
private BeltPortHost _insertLogic = default!;
|
||||
public IBeltPortHost Value() => _insertLogic;
|
||||
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn<IVoxelGridRegistry>();
|
||||
[Dependency] public IRecipes Recipes => this.DependOn<IRecipes>();
|
||||
IVoxelGridRegistry IProvide<IVoxelGridRegistry>.Value() => GridRegistry;
|
||||
public GridTransform3D VoxelTransform
|
||||
{
|
||||
get => GridTransform3D.FromGodot(GlobalTransform);
|
||||
set => GlobalTransform = value.ToGodot();
|
||||
}
|
||||
private Entity _itemBeingHeld = Entity.Null;
|
||||
private VoxelGuid _guid;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
_insertLogic = new BeltPortHost();
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.PortName == "Input", () => new DelegateInsertBeltItemLogic(canAccept, canInsert));
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.PortName == "OutPut", () => new DelegateInsertBeltItemLogic((_, _) => false, (_, _) => false));
|
||||
bool canAccept(IBeltPort port, IBeltItem item) => _itemBeingHeld.Id == -1 && !_itemBeingHeld.IsAlive();
|
||||
bool canInsert(IBeltPort beltPort, IBeltItem item)
|
||||
{
|
||||
if (item is IBeltItemData<Entity> itemData)
|
||||
{
|
||||
_itemBeingHeld = itemData.GetItem();
|
||||
item.Dispose();
|
||||
GD.Print("Added Item");
|
||||
return true;
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
_guid = GridRegistry.Register(this, VoxelTransform.Origin);
|
||||
this.Provide();
|
||||
|
||||
var time = new Timer() { Autostart = true, OneShot = false, WaitTime = .1 };
|
||||
AddChild(time);
|
||||
|
||||
time.Timeout += () =>
|
||||
{
|
||||
if (_itemBeingHeld.Id == -1 && !_itemBeingHeld.IsAlive())//TODO have a better way of dertming if item is valid, possibly nullable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_itemBeingHeld.TryGet<Temperature>(out var temp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
temp.Kelvin += new TemperatureDelta(5f, TemperatureUnit.Fahrenheit).KelvinDelta;
|
||||
_itemBeingHeld.Set(temp);
|
||||
|
||||
Span<Entity> items = [_itemBeingHeld];
|
||||
var context = new RecipeContext(World.Worlds[0], items);
|
||||
var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
|
||||
Span<int> mapping = stackalloc int[1];
|
||||
var recipes = Recipes.GetRecipes(new RecipeAction("cook"), 1, [_itemBeingHeld.Get<Tags>()], [], RecipeOutput.Any, mapping);
|
||||
// Span<Entity> created = stackalloc Entity[10];
|
||||
unsafe
|
||||
{
|
||||
while (RecipeProcessor.TryProcess(
|
||||
ref recipes,
|
||||
ref context,
|
||||
ref builder,
|
||||
&DestroyEntity,
|
||||
out var created
|
||||
))
|
||||
{
|
||||
Debug.Assert(created.Length <= 1);
|
||||
|
||||
_itemBeingHeld = created[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
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))
|
||||
{
|
||||
_itemBeingHeld = Entity.Null;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static void DestroyEntity(Entity entity) => World.Worlds[entity.WorldId].Destroy(entity);
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
GridRegistry.UnRegister(_guid);
|
||||
base._ExitTree();
|
||||
}
|
||||
}
|
||||
public class DelegateInsertBeltItemLogic : IBeltItemInsertLogic
|
||||
{
|
||||
private readonly Func<IBeltPort, IBeltItem, bool> _canAccept;
|
||||
private readonly Func<IBeltPort, IBeltItem, bool> _canInsert;
|
||||
|
||||
public DelegateInsertBeltItemLogic(Func<IBeltPort, IBeltItem, bool> canAccept, Func<IBeltPort, IBeltItem, bool> canInsert)
|
||||
{
|
||||
_canAccept = canAccept;
|
||||
_canInsert = canInsert;
|
||||
}
|
||||
|
||||
public bool CanAccept(IBeltPort beltPort, IBeltItem item) => _canAccept(beltPort, item);
|
||||
public bool CanInsert(IBeltPort beltPort, IBeltItem item) => _canInsert(beltPort, item);
|
||||
}
|
||||
public readonly ref struct RecipeMatch
|
||||
{
|
||||
public readonly Recipe Recipe;
|
||||
public readonly ReadOnlySpan<int> Mapping;
|
||||
|
||||
public RecipeMatch(
|
||||
Recipe recipe,
|
||||
ReadOnlySpan<int> mapping)
|
||||
{
|
||||
Recipe = recipe;
|
||||
Mapping = mapping;
|
||||
}
|
||||
}
|
||||
public interface IRecipeEnumerator
|
||||
{
|
||||
RecipeMatch Current { get; }
|
||||
|
||||
bool MoveNext();
|
||||
}
|
||||
public unsafe ref struct RecipeEnumerator : IRecipeEnumerator
|
||||
{
|
||||
public readonly RecipeMatch Current => _match;
|
||||
private RecipeMatch _match;
|
||||
private int _index;
|
||||
private readonly ReadOnlySpan<CompiledRecipe> _recipes;
|
||||
private readonly RecipeInput _input;
|
||||
private readonly Span<int> _mapping;
|
||||
private readonly delegate*<RecipeInput, CompiledRecipe, Span<int>, out RecipeMatch, bool> _filter;
|
||||
public RecipeEnumerator(ReadOnlySpan<CompiledRecipe> compiledRecipes, RecipeInput input, delegate*<RecipeInput, CompiledRecipe, Span<int>, out RecipeMatch, bool> filter, Span<int> mapping)
|
||||
{
|
||||
_recipes = compiledRecipes;
|
||||
_input = input;
|
||||
_index = -1;
|
||||
_filter = filter;
|
||||
_mapping = mapping;
|
||||
}
|
||||
public bool MoveNext()
|
||||
{
|
||||
_index++;
|
||||
while (_index < _recipes.Length)
|
||||
{
|
||||
if (_filter(_input, _recipes[_index], _mapping, out _match))
|
||||
{
|
||||
break;
|
||||
}
|
||||
_index++;
|
||||
|
||||
}
|
||||
return _index < _recipes.Length;
|
||||
|
||||
}
|
||||
}
|
||||
public static class RecipeProcessor
|
||||
{
|
||||
public static unsafe bool TryProcess<TRecipeEnumerator>(
|
||||
ref TRecipeEnumerator recipes,
|
||||
scoped ref RecipeContext context,
|
||||
scoped ref RecipeResultBuilder builder,
|
||||
delegate*<Entity, void> destroyEntity,
|
||||
out Span<Entity> resultEntity)
|
||||
where TRecipeEnumerator : IRecipeEnumerator, allows ref struct
|
||||
{
|
||||
resultEntity = default;
|
||||
|
||||
while (recipes.MoveNext())
|
||||
{
|
||||
var entry = recipes.Current;
|
||||
|
||||
var recipe = entry.Recipe;
|
||||
|
||||
if (!recipe.CanProcess(context))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = recipe.Process(context, ref builder);
|
||||
|
||||
ApplyResult(
|
||||
in context,
|
||||
result,
|
||||
destroyEntity,
|
||||
out resultEntity);
|
||||
|
||||
builder.Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static unsafe void ApplyResult(
|
||||
scoped in RecipeContext context,
|
||||
scoped RecipeResult result,
|
||||
delegate*<Entity, void> destroyEntity,
|
||||
out Span<Entity> created)
|
||||
{
|
||||
created = default;
|
||||
|
||||
|
||||
result.Mutate?.Invoke(context);
|
||||
created = new Entity[result.CreateLength];
|
||||
for (int i = 0; i < result.CreateLength; i++)
|
||||
{
|
||||
created[i] = result.Create[i](in context);
|
||||
|
||||
}
|
||||
|
||||
if (result.RemoveLength > 0)
|
||||
{
|
||||
for (var i = 0; i < result.RemoveLength; i++)
|
||||
{
|
||||
if (result.Remove[i])
|
||||
{
|
||||
destroyEntity(context.Items[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://cnkblltup5guy
|
||||
@@ -1,106 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Arch.Core;
|
||||
using Arch.Core.Extensions;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory;
|
||||
using FoodFactory.Items;
|
||||
using FoodFactory.Recipes;
|
||||
using Godot;
|
||||
using SJK.Functional;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class SlicerTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxelGridRegistry>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
private BeltPortHost _insertLogic = default!;
|
||||
public IBeltPortHost Value() => _insertLogic;
|
||||
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn<IVoxelGridRegistry>();
|
||||
[Dependency] public IRecipes Recipes => this.DependOn<IRecipes>();
|
||||
IVoxelGridRegistry IProvide<IVoxelGridRegistry>.Value() => GridRegistry;
|
||||
public GridTransform3D VoxelTransform
|
||||
{
|
||||
get => GridTransform3D.FromGodot(GlobalTransform);
|
||||
set => GlobalTransform = value.ToGodot();
|
||||
}
|
||||
private Entity _itemBeingHeld = Entity.Null;
|
||||
private List<Entity> sliced = [];
|
||||
private VoxelGuid _guid;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
_insertLogic = new BeltPortHost();
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.PortName == "Input", () => new DelegateInsertBeltItemLogic(canAccept, canInsert));
|
||||
_insertLogic.Bind(port => port is BeltPort beltPort && beltPort.PortName == "OutPut", () => new DelegateInsertBeltItemLogic((_, _) => false, (_, _) => false));
|
||||
bool canAccept(IBeltPort port, IBeltItem item) => _itemBeingHeld.Id == -1 && !_itemBeingHeld.IsAlive() && item is IBeltItemData<Entity> beltItemData && beltItemData.GetItem().TryGet<Tags>(out var tags) && tags.Contains(TagRegistry.GetTag("sliceable"));
|
||||
bool canInsert(IBeltPort beltPort, IBeltItem item)
|
||||
{
|
||||
if (item is IBeltItemData<Entity> itemData)
|
||||
{
|
||||
_itemBeingHeld = itemData.GetItem();
|
||||
item.Dispose();
|
||||
GD.Print("Added Item to slicer");
|
||||
return true;
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
_guid = GridRegistry.Register(this, VoxelTransform.Origin);
|
||||
this.Provide();
|
||||
|
||||
var time = new Timer() { Autostart = true, OneShot = false, WaitTime = .1 };
|
||||
AddChild(time);
|
||||
|
||||
time.Timeout += () =>
|
||||
{
|
||||
|
||||
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))
|
||||
{
|
||||
GD.Print(sliced[0].Get<Carbohydrates>());
|
||||
sliced.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
if (_itemBeingHeld.Id == -1)//TODO have a better way of dertming if item is valid, possibly nullable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Span<Entity> items = [_itemBeingHeld];
|
||||
var context = new RecipeContext(World.Worlds[0], items);
|
||||
var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
|
||||
Span<int> mapping = stackalloc int[1];
|
||||
// var recipe = new PotatoCookRecipe();
|
||||
var recipes = Recipes.GetRecipes("slice", 1, [_itemBeingHeld.Get<Tags>()], [], new RecipeOutput(2), mapping);
|
||||
unsafe
|
||||
{
|
||||
while (RecipeProcessor.TryProcess(
|
||||
ref recipes,
|
||||
ref context,
|
||||
ref builder,
|
||||
&DestroyEntity,
|
||||
out var created
|
||||
))
|
||||
{
|
||||
_itemBeingHeld = Entity.Null;
|
||||
sliced.AddRange(created);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
private static void DestroyEntity(Entity entity) => World.Worlds[entity.WorldId].Destroy(entity);
|
||||
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
GridRegistry.UnRegister(_guid);
|
||||
base._ExitTree();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://yec84plemjv1
|
||||
@@ -1,574 +0,0 @@
|
||||
namespace ChickenGameTest;
|
||||
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.AutoInject;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Chickensoft.Sync.Primitives;
|
||||
using SJK.Functional;
|
||||
using FoodFactory.Recipes;
|
||||
using Arch.Core;
|
||||
|
||||
public class Sorted1DList<T>
|
||||
{
|
||||
private readonly AutoList<T> _items = [];
|
||||
#if DEBUG
|
||||
private readonly AutoList<T>.Binding _binding;
|
||||
#endif
|
||||
private readonly Func<T, float> _getPosition;
|
||||
public Sorted1DList(Func<T, float> getPos)
|
||||
{
|
||||
_getPosition = getPos;
|
||||
// return;
|
||||
#if DEBUG
|
||||
_binding = _items.Bind();
|
||||
_binding.OnUpdate((a, b, c) =>
|
||||
{
|
||||
// GD.PrintS("++++++++++++++++",a,b,c);
|
||||
});
|
||||
// return;
|
||||
_binding.OnModify(() =>
|
||||
{
|
||||
for (int i = 1; i < _items.Count; i++)
|
||||
{
|
||||
if (_getPosition(_items[i - 1]) >= _getPosition(_items[i]))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"AutoList not sorted at index {i - 1} → {i}. ({_getPosition(_items[i - 1])},{_getPosition(_items[i])})");
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
}
|
||||
public int Count => _items.Count;
|
||||
public IAutoList<T> Items => _items;
|
||||
public IEnumerable<ItemHandle> EnumerateTowardEnd(int? startIndex = null)
|
||||
{
|
||||
if (startIndex.HasValue && startIndex >= Count)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"{nameof(startIndex)}:{startIndex} can not be greater then or equal to {nameof(Count)}:{Count}");
|
||||
}
|
||||
for (int i = Mathf.Max(0, startIndex ?? 0); i < _items.Count; i++)
|
||||
{
|
||||
bool removed = false;
|
||||
yield return new(_items[i],
|
||||
() =>
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
throw new NotSupportedException($"{nameof(ItemHandle.Remove)} can only be called once per item.");
|
||||
}
|
||||
removed = true;
|
||||
_items.RemoveAt(i);
|
||||
i--;
|
||||
},
|
||||
(replaced) =>
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
throw new NotSupportedException("Can not Replace an Item after Removing it");
|
||||
}
|
||||
_items[i] = replaced;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
public IEnumerable<ItemHandle> EnumerateTowardStart(int? startIndex = null)
|
||||
{
|
||||
if (startIndex.HasValue && startIndex < 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"{nameof(startIndex)}:{startIndex} can not be less than zero");
|
||||
}
|
||||
for (int i = Math.Min(startIndex ?? (_items.Count - 1), _items.Count - 1); i >= 0; i--)
|
||||
{
|
||||
bool removed = false;
|
||||
yield return new(_items[i],
|
||||
() =>
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
throw new NotSupportedException($"{nameof(ItemHandle.Remove)} can only be called once per item.");
|
||||
}
|
||||
removed = true;
|
||||
_items.RemoveAt(i);
|
||||
// i--;
|
||||
},
|
||||
(replaced) =>
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
throw new NotSupportedException("Can not Replace an Item after Removing it");
|
||||
}
|
||||
|
||||
if (i - 1 >= 0 && _getPosition(_items[i - 1]) >= _getPosition(replaced))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
if (i + 1 < Count && _getPosition(_items[i + 1]) <= _getPosition(replaced))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
_items[i] = replaced;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
public void Insert(T item)
|
||||
{
|
||||
float pos = _getPosition(item);
|
||||
if (_items.Count == 0 || pos >= _getPosition(_items[^1]))
|
||||
{
|
||||
_items.Add(item);
|
||||
return;
|
||||
}
|
||||
if (pos <= _getPosition(_items[0]))
|
||||
{
|
||||
_items.Insert(0, item);
|
||||
return;
|
||||
}
|
||||
var index = LowerBound(pos);
|
||||
_items.Insert(index, item);
|
||||
}
|
||||
private int LowerBound(float pos)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = _items.Count;
|
||||
|
||||
while (lo < hi)
|
||||
{
|
||||
int mid = (lo + hi) >> 1;
|
||||
|
||||
if (_getPosition(_items[mid]) < pos)
|
||||
{
|
||||
lo = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return lo;
|
||||
}
|
||||
public (Option<T> lower, Option<T> upper) GetNeighbors(float pos)
|
||||
{
|
||||
int index = LowerBound(pos);
|
||||
|
||||
var lower = index > 0 ? Option<T>.Some(_items[index - 1]) : Option<T>.None;
|
||||
var upper = index < _items.Count ? Option<T>.Some(_items[index]) : Option<T>.None;
|
||||
|
||||
return (lower, upper);
|
||||
}
|
||||
public readonly struct ItemHandle
|
||||
{
|
||||
private readonly Action _remove;
|
||||
private readonly Action<T> _replace;
|
||||
public T Value { get; }
|
||||
public ItemHandle(T value, Action remove, Action<T> replace)
|
||||
{
|
||||
Value = value;
|
||||
_remove = remove;
|
||||
_replace = replace;
|
||||
}
|
||||
public void Remove() => _remove();
|
||||
public void Replace(T slice) => _replace(slice);
|
||||
}
|
||||
}
|
||||
[Meta(typeof(IAutoNode))]
|
||||
[Tool]
|
||||
public partial class TestItemConveyor : Node, IMovementConveyor
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Dependency] public IBeltMovement MovementSystem => this.DependOn<IBeltMovement>(() => new IndividualMovement());
|
||||
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn<IVoxelGridRegistry>();
|
||||
// private readonly AutoList<ConveyorSlice> _items = [];
|
||||
// public IAutoList<ConveyorSlice> Items => _items;
|
||||
public readonly Sorted1DList<ConveyorSlice> Items = new(pos => pos.BeltT);
|
||||
// private AutoList<ConveyorSlice>.Binding _itemsBinding;
|
||||
public IBeltPort StartPort { get; set; }
|
||||
// public IBeltSlotProfile StartPort => new ItemConveyor.ConveyorPort() {
|
||||
// Face = Direction.Back,
|
||||
// MovementConveyor = this,
|
||||
// LocalOffset = Position,
|
||||
// BeltT = new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.Start),
|
||||
// PullPush = TransferMode.PushPull ,
|
||||
// Direction = PortAccess.BiDirectional,
|
||||
// AcceptItemFunc = (item,offset)=>{ _items.Insert(0,new ConveyorSlice(item,offset)); return true;},
|
||||
// CanAcceptItemFunc = (item, offset) =>
|
||||
// {
|
||||
// return .25f <= GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, 0, 5f, LaneSpan.One);
|
||||
// }
|
||||
// };
|
||||
public IBeltPort EndPort { get; set; }
|
||||
// public IBeltSlotProfile EndPort => new ItemConveyor.ConveyorPort() {
|
||||
// Face = Direction.Front,
|
||||
// MovementConveyor = this,
|
||||
// Direction = PortAccess.BiDirectional,
|
||||
// LocalOffset = Position,
|
||||
// BeltT = new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.End),
|
||||
// PullPush = TransferMode.PushPull,
|
||||
// AcceptItemFunc = (item,offset)=>{ _items.Add(new ConveyorSlice(item,Length-offset)); return true;},
|
||||
// CanAcceptItemFunc = (item,offset)=> .25f >= GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardStart,Length,.5f,LaneSpan.One)
|
||||
// };
|
||||
public IList<IBeltPort> OtherPorts = [];
|
||||
// [Export] public Vector3I Position { get; set; } = default!;
|
||||
//Speed per unit time
|
||||
private readonly AutoValue<float> _speed = new(1);
|
||||
public IAutoValue<float> SpeedValue => _speed;
|
||||
|
||||
public float SignedSpeed
|
||||
{
|
||||
get => _speed.Value;
|
||||
set => _speed.Value = value;
|
||||
}
|
||||
|
||||
public float SpeedMagnitude
|
||||
{
|
||||
get => Mathf.Abs(_speed.Value);
|
||||
set => _speed.Value = Mathf.Abs(value) * Mathf.Sign(_speed.Value);
|
||||
}
|
||||
public bool IsReversed { get => _speed.Value < 0; set => _speed.Value = SpeedMagnitude * (value ? -1 : 1); }
|
||||
// public IList<ConveyorSlice> Items => _items;
|
||||
public float Length { get; set; } = 1;
|
||||
|
||||
// public IEnumerable<ConveyorSlice> EnumerateTowardEnd() => _items;
|
||||
|
||||
// public IEnumerable<ConveyorSlice> EnumerateTowardStart() => _items.Reverse();
|
||||
public BeltDirection GetBeltDirection() => IsReversed ? BeltDirection.TowardStart : BeltDirection.TowardEnd;
|
||||
public IBeltMovement GetMovementPolicy() => MovementSystem;
|
||||
public IEnumerable<IBeltPort> GetPorts() => [StartPort, EndPort, .. OtherPorts];
|
||||
public void OnResolved()
|
||||
{
|
||||
if (Engine.IsEditorHint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var timer = new Timer() { WaitTime = .05f, Autostart = true };
|
||||
AddChild(timer);
|
||||
timer.Timeout += () => MovementSystem.AdvanceBelt(this, (float)timer.WaitTime);
|
||||
if (StartPort is null || EndPort is null)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
foreach (var item in GetPorts())
|
||||
{
|
||||
var points = item.Points();
|
||||
var guid = GridRegistry.Register(item, [.. points]);
|
||||
TreeExiting += () => GridRegistry.UnRegister(guid);
|
||||
}
|
||||
}
|
||||
//ChatGPT Assisted
|
||||
public BeltObstacle GetDistanceToNextItem(
|
||||
BeltDirection beltDirection,
|
||||
float itemBeltT,
|
||||
float maxDistToCheck,
|
||||
LaneSpan laneSpan,
|
||||
HashSet<IMovementConveyor>? visited = null)
|
||||
{
|
||||
if (beltDirection == BeltDirection.NotMoving)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
visited ??= [];
|
||||
if (!visited.Add(this))
|
||||
{
|
||||
return new BeltObstacle(0);
|
||||
}
|
||||
|
||||
bool towardStart = beltDirection == BeltDirection.TowardStart;
|
||||
|
||||
// 1️⃣ Try to find next item on this conveyor
|
||||
var nextItem = FindNextLocalItem(towardStart, itemBeltT, laneSpan);
|
||||
// GD.Print(nextItem);
|
||||
if (nextItem.HasValue(out var item))
|
||||
{
|
||||
return new ItemBeltObstacle(MathF.Abs(itemBeltT - item.BeltT) - ITEMSIZE, item, laneSpan);
|
||||
// return MathF.Abs(itemBeltT - item.BeltT);//TODO UseLaneSpan inadditon
|
||||
}
|
||||
|
||||
// 2️⃣ No local item → try crossing into adjacent conveyor
|
||||
return GetDistanceAcrossPort(
|
||||
towardStart,
|
||||
itemBeltT,
|
||||
maxDistToCheck,
|
||||
laneSpan,
|
||||
visited
|
||||
);
|
||||
}
|
||||
//ChatGPT Assisted
|
||||
private IOption<ConveyorSlice> FindNextLocalItem(
|
||||
bool towardStart,
|
||||
float itemBeltT,
|
||||
LaneSpan laneSpan)
|
||||
{
|
||||
var sequence = towardStart
|
||||
? EnumerateTowardStart()
|
||||
: EnumerateTowardEnd();
|
||||
|
||||
return sequence
|
||||
.Where(i => towardStart ? i.Value.BeltT < itemBeltT : i.Value.BeltT > itemBeltT)
|
||||
.Where(i => LaneSpan.OverLaps(i.Value.LaneSpan, laneSpan))
|
||||
.Select(item => item.Value)
|
||||
.FirstOrNone();
|
||||
}
|
||||
//ChatGPT Assisted
|
||||
private BeltObstacle GetDistanceAcrossPort(
|
||||
bool towardStart,
|
||||
float itemBeltT,
|
||||
float maxDistToCheck,
|
||||
LaneSpan laneSpan,
|
||||
HashSet<IMovementConveyor> visited)
|
||||
{
|
||||
var port = towardStart ? StartPort : EndPort;
|
||||
var boundaryT = towardStart ? 0f : Length;
|
||||
var distanceToBoundary = MathF.Abs(itemBeltT - boundaryT);
|
||||
|
||||
// 🚫 Boundary already exceeds budget
|
||||
// if (distanceToBoundary >= maxDistToCheck)
|
||||
// {
|
||||
// return maxDistToCheck;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
var neighborPort = FindFacingConveyorPort(port);
|
||||
if (!neighborPort.HasValue(out var conveyorPort))
|
||||
{
|
||||
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
|
||||
}
|
||||
return new BoundaryBeltObstacle(distanceToBoundary);
|
||||
}
|
||||
|
||||
if (conveyorPort.BeltT is not BeltTEnd end)
|
||||
{
|
||||
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
|
||||
: conveyorPort.Conveyor.Length;
|
||||
|
||||
// 🔻 Remaining budget after reaching boundary
|
||||
// var remainingDist = maxDistToCheck - distanceToBoundary;
|
||||
// if (remainingDist <= 0f)
|
||||
// {
|
||||
// return maxDistToCheck;
|
||||
// }
|
||||
|
||||
var recursiveDistance =
|
||||
conveyorPort.Conveyor.GetDistanceToNextItem(
|
||||
nextDirection,
|
||||
startT,
|
||||
maxDistToCheck,
|
||||
lane,
|
||||
visited
|
||||
);
|
||||
return recursiveDistance with { Distance = recursiveDistance.Distance + distanceToBoundary };
|
||||
}
|
||||
private IOption<ConveyorPort> FindFacingConveyorPort(
|
||||
IBeltPort slot)
|
||||
{
|
||||
var targetpos = slot.Profile.LocalOffset.TransformDirection(Vector3I.Forward);
|
||||
// var targetPos = port.Profile.Position + port.Profile.Face.ToVector();
|
||||
return GridRegistry
|
||||
.Get<IBeltPort>(slot.Profile.LocalOffset.LocalToWorld(Vector3I.Forward))
|
||||
|
||||
.Where(port => port is ConveyorPort)
|
||||
.Where(port => port.Profile.LocalOffset.TransformDirection(Vector3I.Forward) == slot.Profile.LocalOffset.TransformDirection(Vector3I.Back))
|
||||
.FirstOrNone()
|
||||
.Bind(p => p is ConveyorPort cp
|
||||
? cp.ToOption()
|
||||
: 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();
|
||||
public IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardStart() => Items.EnumerateTowardStart();
|
||||
private static readonly Vector3[] _square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), new(.5f, -.5f, -.5f), new(-.5f, -.5f, -.5f), new(-.5f, .5f, -.5f)];
|
||||
public const float ITEMSIZE = .2f;
|
||||
private const float ITEMHALFSIZE = ITEMSIZE / 2f;
|
||||
|
||||
// public override void _Process(double delta)
|
||||
// {
|
||||
// if (StartPort is null || EndPort is null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// foreach (var item in GetPorts())
|
||||
// {
|
||||
// for (int ii = 0; ii < item.Profile.Width; ii++)
|
||||
// {
|
||||
// DebugDraw3D.DrawLinePath(_square.Select(i => item.Profile.LocalOffset.ToGodot().TranslatedLocal(i).TranslatedLocal(new Vector3(ii, 0, 0)).Origin).ToArray(), (!Engine.IsEditorHint()) && GetPortFacing(item).HasValue() ? Colors.Green : Colors.Red);
|
||||
|
||||
// }
|
||||
// // DebugDraw3D.DrawArrow(item.Profile.LocalOffset.Origin, item.Profile.LocalOffset.LocalToWorld(item.Profile.Face.ToVector()),(!Engine.IsEditorHint())&&GetPortFacing(item).HasValue()?Colors.Green:Colors.Red);
|
||||
// }
|
||||
// }
|
||||
|
||||
public ConveyorPort CreatePort(BeltPortProfile profile, BeltT beltT, LaneSpan laneSpan)
|
||||
{
|
||||
// var towardStartEnd = beltT is ItemConveyor.BeltTEnd end && end.End == ItemConveyor.ConveyorEnd.End;
|
||||
bool accept(IBeltItem item, float offset, LaneSpan lane)
|
||||
{
|
||||
if (beltT is BeltTEnd end)
|
||||
{
|
||||
var startBeltT = end.End == ConveyorEnd.Start ? 0 : Length;
|
||||
var obstacle = GetDistanceToNextItem(end.End.Swap().DirectionTo(), startBeltT, offset, lane);
|
||||
var distanceAllowed = obstacle.Distance;
|
||||
return ITEMSIZE < distanceAllowed;
|
||||
}
|
||||
else if (beltT is BeltTOffset endOffset)
|
||||
{
|
||||
return HasClearance(endOffset.T, lane);
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
bool tryInsert(IBeltItem item, float offset, LaneSpan laneSpan)
|
||||
{
|
||||
if (beltT is BeltTEnd end)
|
||||
{
|
||||
if (end.End == ConveyorEnd.End)
|
||||
{
|
||||
Items.Insert(new(item, Length - offset) { LaneSpan = laneSpan });
|
||||
// _items.Add(new(item, Length-offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
Items.Insert(new(item, offset) { LaneSpan = laneSpan });
|
||||
// _items.Insert(0, new(item, offset));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (beltT is BeltTOffset endOffset)
|
||||
{
|
||||
|
||||
if (!HasClearance(endOffset.T, LaneSpan.One))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Items.Insert(new(item, endOffset.T) { LaneSpan = laneSpan });
|
||||
// int insertIndex = FindInsertIndex(endOffset.T);
|
||||
|
||||
// _items.Insert(insertIndex, new(item, endOffset.T));
|
||||
|
||||
return true;
|
||||
}
|
||||
// _items.Insert(0,new ConveyorSlice(item,0));
|
||||
// return true;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var port = new ConveyorPort(this,
|
||||
profile,
|
||||
beltT,
|
||||
accept,
|
||||
tryInsert);
|
||||
return port;
|
||||
}
|
||||
private bool HasClearance(float centerT, LaneSpan span)
|
||||
{
|
||||
var lower = GetDistanceToNextItem(
|
||||
BeltDirection.TowardStart,
|
||||
centerT,
|
||||
ITEMSIZE,
|
||||
span
|
||||
);
|
||||
|
||||
var upper = GetDistanceToNextItem(
|
||||
BeltDirection.TowardEnd,
|
||||
centerT,
|
||||
ITEMSIZE,
|
||||
span
|
||||
);
|
||||
|
||||
float lowerAllowed =
|
||||
lower.Distance;// -
|
||||
// (lower.IsItem ? ItemConveyor.ITEMSIZE : 0);
|
||||
|
||||
float upperAllowed =
|
||||
upper.Distance;// -
|
||||
// (upper.IsItem ? ItemConveyor.ITEMSIZE : 0);
|
||||
|
||||
return ITEMSIZE < lowerAllowed &&
|
||||
ITEMSIZE < upperAllowed;
|
||||
}
|
||||
|
||||
}
|
||||
//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 BoundaryBeltObstacle(float DistanceToBoundary) : BeltObstacle(DistanceToBoundary);
|
||||
public record PortBeltObstacle(float DistanceToBoundary, LaneSpan LaneSpan, IBeltPort BeltPort) : BoundaryBeltObstacle(DistanceToBoundary);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
uid://j24fuotdwwx4
|
||||
@@ -1,15 +1,15 @@
|
||||
namespace ChickenGameTest;
|
||||
namespace FoodFactory.Voxel;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Arch.Core;
|
||||
using Arch.Core.Extensions;
|
||||
using Arch.LowLevel;
|
||||
using Arch.System;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory;
|
||||
using FoodFactory.Conveyors;
|
||||
using FoodFactory.Math;
|
||||
using FoodFactory.Recipes;
|
||||
using Godot;
|
||||
public class BacterialSystem : BaseSystem<World, float>
|
||||
@@ -23,7 +23,7 @@ public class BacterialSystem : BaseSystem<World, float>
|
||||
public override void Update(in float t)
|
||||
{
|
||||
var delta = t;
|
||||
World.ParallelQuery(in _desc, (Entity entity, ref Bacteria bacteria, ref Temperature temperature) =>
|
||||
World.Query(in _desc, (Entity entity, ref Bacteria bacteria, ref Temperature temperature) =>
|
||||
{
|
||||
var handle = bacteria.Data;
|
||||
var data = Resources.Get(in handle);
|
||||
@@ -94,7 +94,7 @@ public partial class VoxelGridNode : Node3D, IProvide<IVoxelGridRegistry>, IProv
|
||||
{
|
||||
if (item is ConveyorBeltStraight conveyor)
|
||||
{
|
||||
var node = conveyor.GetNode("Node") as TestItemConveyor;
|
||||
var node = conveyor.ConveyorLogic;
|
||||
node.IsReversed = !node.IsReversed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
namespace ChickenGameTest;
|
||||
namespace FoodFactory.Voxel;
|
||||
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SJK.Functional;
|
||||
using FoodFactory.Items;
|
||||
|
||||
public interface IVoxelGridRegistry
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user