removed Structural instance and SJKScript was changed to be using an nuget package.

This commit is contained in:
2026-04-19 00:46:18 -04:00
parent 5906f248f4
commit e7ef3896b0
21 changed files with 132 additions and 1060 deletions

View File

@@ -1,133 +0,0 @@
namespace ChickenGameTest;
using System;
using System.Collections.Generic;
// public partial class StructuralInstance<TAttribute> where TAttribute : class
// {
public sealed class StructuralBuilder<TAttribute> where TAttribute : class
{
private readonly Dictionary<int, TAttribute> _components = [];
public StructuralBuilder() { }
public StructuralBuilder(IStructuralInstance<TAttribute> existing)
{
foreach (var (id, value) in existing.GetAttributes())
{
_components[id] = value;
}
// for (int i = 0; i < existing.ComponentCount; i++)
// {
// var typeId = existing._attributesTypeIds[i];
// var component = existing.GetComponentAt(i);
// _components[typeId] = component;
// }
}
public StructuralBuilder<TAttribute> Add<T>(T component) where T : TAttribute
{
int id = ComponentTypeRegistry.GetId<T>();
_components[id] = component;
return this;
}
public StructuralBuilder<TAttribute> Upsert<T>(Func<T, T> ifExists, Func<T> none) where T : TAttribute
{
int id = ComponentTypeRegistry.GetId<T>();
_components[id] = _components.TryGetValue(id, out var old) ? ifExists((T)old) : none();
return this;
}
public StructuralBuilder<TAttribute> CombineWith(IStructuralInstance<TAttribute> other, Action<CombineBinder>? configure = null)
{
var binder = new CombineBinder();
configure?.Invoke(binder);
foreach (var (id, value) in other.GetAttributes())
{
if (binder._ignores.Contains(id))
{
continue;
}
if (_components.TryGetValue(id, out var existing)
&& binder._rules.TryGetValue(id, out var rule))
{
_components[id] = rule.Invoke(existing, value);
continue;
}
_components[id] = value;
}
return this;
}
public StructuralBuilder<TAttribute> Remove<T>() where T : TAttribute
{
int id = ComponentTypeRegistry.GetId<T>();
_components.Remove(id);
return this;
}
public bool Has<T>() where T : TAttribute
{
int id = ComponentTypeRegistry.GetId<T>();
return _components.ContainsKey(id);
}
public StructuralInstance<TAttribute> Build()
{
int count = _components.Count;
var typeIds = new int[count];
var components = new TAttribute[count];
int i = 0;
foreach (var kv in _components)
{
typeIds[i] = kv.Key;
components[i] = kv.Value;
i++;
}
Array.Sort(typeIds, components);
return new StructuralInstance<TAttribute>(typeIds, components);
}
public MutableStructuralInstance<TAttribute> BuildMutable()
{
// int count = _components.Count;
var sortedList = new SortedList<int, TAttribute>(_components);
// var typeIds = new int[count];
// var components = new TAttribute[count];
// int i = 0;
// foreach (var kv in _components)
// {
// typeIds[i] = kv.Key;
// components[i] = kv.Value;
// i++;
// }
// Array.Sort(typeIds, components);
return new MutableStructuralInstance<TAttribute>(sortedList);
}
public class CombineBinder
{
internal readonly Dictionary<int, Func<TAttribute, TAttribute, TAttribute>> _rules = [];
internal readonly HashSet<int> _ignores = [];
public CombineBinder Bind<T>(Func<T, T, T> func) where T : TAttribute
{
_rules[ComponentType<T>.Id] = (a, b) => func((T)a, (T)b);
return this;
}
public CombineBinder Ignore<T>() where T : TAttribute
{
_ignores.Add(ComponentType<T>.Id);
return this;
}
}
}
// }

View File

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

View File

@@ -1,255 +0,0 @@
namespace ChickenGameTest;
using System;
using System.Collections.Generic;
using System.Linq;
using Chickensoft.Sync.Primitives;
using SJK.Functional;
public interface IStructuralInstance<TAttribute> : IEquatable<IStructuralInstance<TAttribute>>
{
int ComponentCount { get; }
bool Has<T>() where T : TAttribute;
Option<T> Get<T>() where T : TAttribute;
// TAttribute GetComponentAt(int index);
IEnumerable<(int Id, TAttribute Value)> GetAttributes();
bool IEquatable<IStructuralInstance<TAttribute>>.Equals(IStructuralInstance<TAttribute>? other) => Enumerable.SequenceEqual(GetAttributes(), other.GetAttributes(), EqualityComparer<(int, TAttribute)>.Default);
int ComputeHashCode()
{
HashCode hash = new HashCode();
foreach (var item in GetAttributes())
{
hash.Add(item);
}
return hash.ToHashCode();
}
}
public sealed partial class StructuralInstance<TAttribute> : IStructuralInstance<TAttribute>, IEquatable<StructuralInstance<TAttribute>> where TAttribute : class
{
private readonly int _hashCode;
internal readonly int[] _attributesTypeIds;
internal readonly TAttribute[] _attributes;
public int ComponentCount => _attributes.Length;
public TAttribute GetComponentAt(int index) => _attributes[index];
internal StructuralInstance(int[] componentTypeIds, TAttribute[] attributes)
{
_attributesTypeIds = componentTypeIds;
_attributes = attributes;
_hashCode = (this as IStructuralInstance<TAttribute>).ComputeHashCode();
}
public bool Has<T>() where T : TAttribute
{
// int typeId = ComponentTypeRegistry.GetId<T>();
var typeId = ComponentType<T>.Id;
return Array.BinarySearch(_attributesTypeIds, typeId) >= 0;
}
public Option<T> Get<T>() where T : TAttribute
{
// int typeId = ComponentTypeRegistry.GetId<T>();
var typeId = ComponentType<T>.Id;
int index = Array.BinarySearch(_attributesTypeIds, typeId);
if (index < 0)
{
return Option<T>.None;
}
return Option<T>.Some((T)_attributes[index]);
}
public bool Equals(StructuralInstance<TAttribute>? other)
{
if (ReferenceEquals(this, other))
{
return true;
}
if (other is null)
{
return false;
}
return _hashCode == other._hashCode && Enumerable.SequenceEqual(_attributes, other._attributes, EqualityComparer<TAttribute>.Default);// && AttributesAreEqual(other);
}
public override bool Equals(object? obj) => obj is StructuralInstance<TAttribute> value? Equals(value) : obj is IStructuralInstance<TAttribute> v && v.Equals(this);
public override int GetHashCode() => _hashCode;
public IEnumerable<(int Id, TAttribute Value)> GetAttributes()
{
for (int i = 0; i < ComponentCount; i++)
{
yield return (_attributesTypeIds[i], _attributes[i]);
}
}
public override string ToString() => base.ToString();
}
public sealed class MutableStructuralInstance<TAttribute> : IStructuralInstance<TAttribute>, IEquatable<MutableStructuralInstance<TAttribute>> where TAttribute : class
{
private readonly SortedList<int, TAttribute> _attributes = [];
public int ComponentCount => _attributes.Count;
public MutableStructuralInstance(SortedList<int, TAttribute> attributes)
{
_attributes = attributes;
}
public Option<T> Get<T>() where T : TAttribute => _attributes.TryGetValue(ComponentType<T>.Id, out var attribute) ? Option<T>.Some((T)attribute) : Option<T>.None;
public IEnumerable<(int Id, TAttribute Value)> GetAttributes() => _attributes.Select(x => (x.Key, x.Value));
public TAttribute GetComponentAt(int index) => _attributes[index];
public bool Has<T>() where T : TAttribute => _attributes.ContainsKey(ComponentType<T>.Id);
public void Set<T>(T value) where T : TAttribute => _attributes[ComponentType<T>.Id] = value;
public override int GetHashCode() => (this as IStructuralInstance<TAttribute>).ComputeHashCode();
public bool Equals(MutableStructuralInstance<TAttribute>? other) => other is not null && Enumerable.SequenceEqual(_attributes, other._attributes, EqualityComparer<KeyValuePair<int, TAttribute>>.Default);
public override bool Equals(object? obj) => obj is MutableStructuralInstance<TAttribute> other ? Equals(other) : obj is IStructuralInstance<TAttribute> v && v.Equals(this);
}
public static class ComponentTypeRegistry
{
private static readonly Dictionary<Type, int> _typeToId = [];
private static readonly List<Type> _idToType = [];
public static int GetId(Type type)
{
if (_typeToId.TryGetValue(type, out var id))
{
return id;
}
id = _idToType.Count;
_typeToId[type] = id;
_idToType.Add(type);
return id;
}
public static int GetId<T>() => GetId(typeof(T));
}
public static class ComponentType<T>
{
public static readonly int Id = ComponentTypeRegistry.GetId<T>();
public static readonly bool CacheTransitions = Resolve();
private static bool Resolve()
{
var attr = typeof(T).GetCustomAttributes(typeof(ComponentOptionsAttribute), false);
return attr.OfType<ComponentOptionsAttribute>().FirstOrNone().Map(static f => f.CacheTransitions).Or(true);
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class ComponentOptionsAttribute : Attribute
{
public bool CacheTransitions { get; init; } = true;
}
public interface IStructureRegistry<TAttribute> where TAttribute : class
{
StructuralInstance<TAttribute> Canonicalize(StructuralInstance<TAttribute> value);
StructuralInstance<TAttribute> AddOrReplaceAttribute<T>(StructuralInstance<TAttribute> instance, T attribute) where T : TAttribute;
StructuralInstance<TAttribute> RemoveAttribute<T>(StructuralInstance<TAttribute> instance) where T : TAttribute;
}
public class StructuralInstanceManger<TAttribute> : IStructureRegistry<TAttribute> where TAttribute : class
{
private readonly HashSet<StructuralInstance<TAttribute>> _instances = [];
public StructuralInstance<TAttribute> Add<T>(StructuralInstance<TAttribute> instance, T component) where T : TAttribute
{
var builder = new StructuralBuilder<TAttribute>(instance).Add(component);
return Canonicalize(builder.Build());
}
public StructuralInstance<TAttribute> Canonicalize(StructuralInstance<TAttribute> value)
{
if (_instances.TryGetValue(value, out var id))
{
return id;
}
_instances.Add(value);
return value;
}
public StructuralInstance<TAttribute> AddOrReplaceAttribute<T>(StructuralInstance<TAttribute> instance, T attribute) where T : TAttribute
{
if (!graph.TryGetValue(instance, out var results))
{
graph[instance] = results = [];
}
for (int i = 0; i < results.Count; i++)
{
if (results[i] is AddTransitionEntry<T> addTransitionEntry && EqualityComparer<T>.Default.Equals(addTransitionEntry.Value, attribute))
{
return addTransitionEntry.Result;
}
}
var result =new AddTransitionEntry<T>(ComponentType<T>.Id, attribute, Canonicalize(new StructuralBuilder<TAttribute>(instance).Add(attribute).Build()));
if (ComponentType<T>.CacheTransitions)
{
results.Add(result);
}
return result.Result;
}
public StructuralInstance<TAttribute> RemoveAttribute<T>(StructuralInstance<TAttribute> instance) where T : TAttribute
{
if (!graph.TryGetValue(instance, out var results))
{
graph[instance] = results = [];
}
var id = ComponentType<T>.Id;
for (int i = 0; i < results.Count; i++)
{
if (results[i] is RemoveTransitionEntry removeTransitionEntry && removeTransitionEntry.Id == id)
{
return removeTransitionEntry.Result;
}
}
var result =new RemoveTransitionEntry(id, Canonicalize(new StructuralBuilder<TAttribute>(instance).Remove<T>().Build()));
if (ComponentType<T>.CacheTransitions)
{
results.Add(result);
}
return result.Result;
}
private Dictionary<StructuralInstance<TAttribute>, List<TransitionEntry>> graph = [];
private record TransitionEntry(int Id);
private record AddTransitionEntry<T>(int Id, T Value, StructuralInstance<TAttribute> Result) : TransitionEntry(Id) where T : TAttribute;
private record RemoveTransitionEntry(int Id, StructuralInstance<TAttribute> Result) : TransitionEntry(Id);
// private record ModifyTransitionEntry<T>(int Id, TAttribute Value, StructuralInstance<TAttribute> Result) : TransitionEntry(Id) where T : TAttribute;
}
public class AutoStructureInstance<TAttribute> where TAttribute : class
{
private StructuralInstance<TAttribute> _structuralInstance;
private IStructureRegistry<TAttribute> _registry;
private Dictionary<int,List<Delegate>> _bindings = [];
public void Set<T>(T? value) where T : TAttribute
{
var old = _structuralInstance.Get<T>();
if (old.HasValue && old.Value.Equals(value))
{
return;
}
if (value is null)
{
_structuralInstance = _registry.RemoveAttribute<T>(_structuralInstance);
}
else
{
_structuralInstance = _registry.AddOrReplaceAttribute(_structuralInstance, value);
}
_bindings[ComponentType<T>.Id].ForEach(item => item.DynamicInvoke(old,value));
}
public void Bind<T>(Action<T?, T?> callback) where T : TAttribute
{
int id = ComponentType<T>.Id;
if (!_bindings.TryGetValue(id, out var list))
{
_bindings[id] = list = [];
}
list.Add(callback);
}
}

View File

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

View File

@@ -1,69 +0,0 @@
namespace ChickenGameTest;
using System.Diagnostics;
using Godot;
using SJK.Functional;
public class TestStructural
{
public static void Test()
{
var a = new StructuralBuilder<object>()
.Add(new Vector3(0,0,0))
.Add(new Vector2(0,5))
.Add(new Vector4(0,0,0,0))
.Add(new Aabb())
.Add(new int())
.Add(new float())
.Add(new Node())
.Add(new Node())
.Add(new Node2D())
.Add("")
.Add(new test(){a = 5, b = "gg"})
.Build();
var registy = new StructuralInstanceManger<object>();
var b = registy.Add(a,new Vector2(1,2));
var c = registy.Add(a,new Vector2(1,2));
var d = registy.Canonicalize(new StructuralBuilder<object>(a).Add(new Vector2(1,2)).Build());
var g = new StructuralBuilder<object>(a).Add(Option<int>.Some(5)).Build();
var h = new StructuralBuilder<object>(a).Add(Option<int>.Some(5)).BuildMutable();
GD.Print(g.Equals(h));
GD.Print(ReferenceEquals(b,c));
GD.Print(ReferenceEquals(b,d));
GD.Print(ComponentType<Vector3>.Id);
GD.Print(ComponentType<Vector2>.Id);
var help = new StructuralBuilder<object>(a)
.CombineWith(b, static configure => configure
.Bind<Vector2>(static (a, b) => a + b)
.Ignore<Vector4>())
.Add(Vector2I.Zero)
.Build();
GD.Print(help.Get<Vector2>().Map(i=>$"{i}").OrDefault("none"));
var timer = new Stopwatch();
timer.Start();
for (int i = 0; i < 100000; i++)
{
var e = registy.AddOrReplaceAttribute(a,new test());
}
timer.Stop();
GD.Print(timer.Elapsed);
timer.Reset();
timer.Start();
for (int i = 0; i < 100000; i++)
{
var e = registy.Canonicalize(new StructuralBuilder<object>(a).Add(new test()).Build());
}
timer.Stop();
GD.Print(timer.Elapsed);
}
}
[ComponentOptions(CacheTransitions = true)]
record test
{
public int a;
public string b;
}

View File

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

View File

@@ -19,12 +19,12 @@ public interface IBeltItem : IDisposable
public class TestItem() : IBeltItem
{
public float Temp {get;set;}
public int Width {get;set;}
public float Temp { get; set; }
public int Width { get; set; }
public int Height {get;set;}
public int Height { get; set; }
public Node3D CreateItemVisual() => new MeshInstance3D(){Mesh = new BoxMesh(){Size = new(.1f,.1f,.1f)}};
public Node3D CreateItemVisual() => new MeshInstance3D() { Mesh = new BoxMesh() { Size = new(.1f, .1f, .1f) } };
bool _disposed;
public event IBeltItem.ItemRemoved Disposed;
@@ -83,7 +83,7 @@ public interface IBeltPort
yield return (Profile.LocalOffset.Right * i) + Profile.LocalOffset.Origin;
}
}
LaneSpan LaneSpan => new LaneSpan(0,(ushort)Profile.Width);
LaneSpan LaneSpan => new(0, (ushort)Profile.Width);
}
public sealed class ConveyorPort : IBeltPort
{
@@ -150,20 +150,10 @@ public sealed class ConveyorPort : IBeltPort
public interface IBeltSlotProfile
{
Vector3I Position { get; }
// Direction Direction { get; }
int Width { get; }
PortAccess Access { get; }
// bool CanAcceptItem(IBeltItem beltItem, LaneSpan laneSpan, float beltT = 0);
// /// <summary>
// ///Tries to insert an belt item offset by laneSpan,
// /// </summary>
// /// <param name="beltItem"></param>
// /// <param name="laneSpan"></param>
// /// <param name="beltT"></param>
// /// <returns></returns>
// bool TryInsertItem(IBeltItem beltItem, LaneSpan laneSpan, float beltT = 0);
}
public record LaneId(int Index);
// public record LaneId(int Index);
[Flags]
public enum PortAccess : byte
{
@@ -181,16 +171,16 @@ public enum TransferMode : byte//Need Better Name
Pull = 2,
PushPull = Push | Pull
}
public static class SlotExtesion
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(
public static LaneSpan MapSlotToFacingSlot(
GridTransform3D fromTx,
int fromWidth,
GridTransform3D toTx,
int toWidth)
{
{
ushort minLane = ushort.MaxValue;
ushort maxLane = ushort.MinValue;
@@ -224,7 +214,7 @@ public static LaneSpan MapSlotToFacingSlot(
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

View File

@@ -1,23 +0,0 @@
using Godot;
public static partial class SJKMath
{
// public static Vector3I Lerp(Vector3I from, Vector3I to, float weight) => new Vector3I(
// Mathf.Lerp(from.X, to.X, weight),
// Mathf.Lerp(from.Y, to.Y, weight),
// Mathf.Lerp(from.Z, to.Z, weight)
// );
public static Vector3 Lerp(Vector3 from, Vector3 to, float weight) => new Vector3(
Mathf.Lerp(from.X, to.X, weight),
Mathf.Lerp(from.Y, to.Y, weight),
Mathf.Lerp(from.Z, to.Z, weight)
);
// public static Vector2I Lerp(Vector2I from, Vector2I to, float weight) => new Vector2I(
// Mathf.Lerp(from.X, to.X, weight),
// Mathf.Lerp(from.Y, to.Y, weight)
// );
public static Vector2 Lerp(Vector2 from, Vector2 to, float weight) => new Vector2(
Mathf.Lerp(from.X, to.X, weight),
Mathf.Lerp(from.Y, to.Y, weight)
);
}

View File

@@ -1 +0,0 @@
uid://133eop5e4mii

View File

@@ -1,42 +0,0 @@
using System;
using System.Linq;
using Godot;
namespace SJK.GodotHelpers;
public static class MyNodeExtensions{
public static void FreeDeferred(this Node node)=>node.CallDeferred(Node.MethodName.Free);
/// <summary>
/// Checks if given Property exists on <c>Base</c>
/// </summary>
/// <param name="Base">Current <c>GodotObject</c></param>
/// <param name="PropertyName">Property Name</param>
/// <returns><c>bool</c> true if given property exists on Base</returns>
public static bool HasProperty(this GodotObject Base, string PropertyName){
/*
Returns the object's property list as an Godot.Collections.Array of dictionaries.
Each Godot.Collections.Dictionary contains the following entries:
- name is the property's name, as a string;
- class_name is an empty StringName, unless the property is Variant.Type.Object and it inherits from a class;
- type is the property's type, as an int (see Variant.Type);
- hint is how the property is meant to be edited (see PropertyHint);
- hint_string depends on the hint (see PropertyHint);
- usage is a combination of PropertyUsageFlags.
*/
foreach (var Property in Base.GetPropertyListEx())
{
if(Property.Name == PropertyName){
return true;
}
}
return false;
}
public static (Node node, Resource resource, NodePath remaining) GetNodeAndResourceEx(this Node self, NodePath path)
{
var result = self.GetNodeAndResource(path);
return ((Node)result[0], (Resource)result[1], (NodePath)result[2]);
}
public static void QueueFreeChildren(this Node node) => node.GetChildren().ToList().ForEach(item=>item.QueueFree());
public static void QueueFreeChildren(this Node node, Func<Node,bool> predicate) => node.GetChildren().Where(predicate).ToList().ForEach(item=>item.QueueFree());
}

View File

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

View File

@@ -1,177 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Godot;
using Godot.Collections;
using SJK.Functional;
namespace SJK.GodotHelpers.Raycasts;
public record CollisionResultBase(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape
);
public record RaycastResult3D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape,
Vector3 Position,
Vector3 Normal
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
public record RaycastResult2D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape,
Vector2 Position,
Vector2 Normal
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
public record ShapeCastResult3D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape,
Vector3 Point,
Vector3 Normal,
int CollisionCount
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
public record ShapeCastResult2D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape,
Vector2 Point,
Vector2 Normal,
int CollisionCount
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
public record PointQueryResult3D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
public record PointQueryResult2D(
GodotObject Collider,
int ColliderId,
Rid Rid,
int Shape
) : CollisionResultBase(Collider, ColliderId, Rid, Shape);
#nullable enable
public static class RaycastExtensions
{
// --- 3D ---
public static RaycastResult3D? RaycastEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
{
var query = new PhysicsRayQueryParameters3D
{
From = from,
To = to,
CollisionMask = collisionMask,
HitFromInside = hitFromInside,
};
if (exclude != null)
query.Exclude = new Array<Rid>(exclude);
var result = space.IntersectRay(query);
if (result.Count == 0)
return null;
return new RaycastResult3D(
Collider: result["collider"].AsGodotObject(),
ColliderId: result["collider_id"].AsInt32(),
Rid: (Rid)result["rid"],
Shape: result["shape"].AsInt32(),
Position: result["position"].AsVector3(),
Normal: result["normal"].AsVector3()
);
}
public static bool RaycastHitEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to,[NotNullWhen(true)] out RaycastResult3D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
{
hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!;
return hit is not null;
}
// --- 2D ---
public static RaycastResult2D? RaycastEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
{
var query = new PhysicsRayQueryParameters2D
{
From = from,
To = to,
CollisionMask = collisionMask,
HitFromInside = hitFromInside,
};
if (exclude != null)
query.Exclude = new Array<Rid>(exclude);
var result = space.IntersectRay(query);
if (result.Count == 0)
return null;
return new RaycastResult2D(
Collider: result["collider"].AsGodotObject(),
ColliderId: result["collider_id"].AsInt32(),
Rid: (Rid)result["rid"],
Shape: result["shape"].AsInt32(),
Position: result["position"].AsVector2(),
Normal: result["normal"].AsVector2()
);
}
public static IOption<RaycastResult2D> RaycastOptionEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
=> RaycastEx(space, from, to, collisionMask, exclude, hitFromInside).ToOption();
public static bool RaycastHitEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, out RaycastResult2D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false)
{
hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!;
return hit is not null;
}
// 3D Shape Cast
public static List<CollisionResultBase> IntersectShapeEx(this PhysicsDirectSpaceState3D space, PhysicsShapeQueryParameters3D query, int maxResults = 32)
{
var results = space.IntersectShape(query, maxResults);
var list = new List<CollisionResultBase>(results.Count);
foreach (var dict in results)
{
list.Add(new CollisionResultBase(
Collider: dict["collider"].AsGodotObject(),
ColliderId: dict["collider_id"].AsInt32(),
Rid: (Rid)dict["rid"],
Shape: dict["shape"].AsInt32()
));
}
return list;
}
// 2D Shape Cast
public static List<CollisionResultBase> IntersectShapeEx(this PhysicsDirectSpaceState2D space, PhysicsShapeQueryParameters2D query, int maxResults = 32)
{
var results = space.IntersectShape(query, maxResults);
var list = new List<CollisionResultBase>(results.Count);
foreach (var dict in results)
{
list.Add(new CollisionResultBase(
Collider: dict["collider"].AsGodotObject(),
ColliderId: dict["collider_id"].AsInt32(),
Rid: (Rid)dict["rid"],
Shape: dict["shape"].AsInt32()
));
}
return list;
}
}

View File

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

View File

@@ -1,121 +0,0 @@
using Godot;
using Godot.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using Array = Godot.Collections.Array;
namespace SJK.GodotHelpers;
/// <summary>
/// Strongtyped view of Godot's get_method_list / get_property_list output.
/// </summary>
public static class Reflector
{
/* ──────────── Typed records ──────────── */
public readonly record struct ArgInfo(
string Name,
Variant.Type Type,
PropertyHint Hint,
string HintString,
Variant DefaultValue);
public readonly record struct MethodInfoEx(
string Name,
IReadOnlyList<ArgInfo> Args,
IReadOnlyList<Variant> DefaultArgs,
MethodFlags Flags,
int Id,
ArgInfo? ReturnValue);
public readonly record struct PropertyInfoEx(
string Name,
string ClassName,
Variant.Type Type,
PropertyHint Hint,
string HintString,
PropertyUsageFlags Usage);
/* ──────────── Public helpers ──────────── */
public static List<MethodInfoEx> GetMethodsListEx(this GodotObject godotObject)=>GetMethods(godotObject);
public static List<MethodInfoEx> GetMethods(GodotObject obj)
{
var raw = obj.GetMethodList();
var list = new List<MethodInfoEx>(raw.Count);
foreach (Dictionary dict in raw)
{
// — Parse args —
var argsRaw = (Array)dict["args"];
var args = new List<ArgInfo>(argsRaw.Count);
foreach (Dictionary a in argsRaw)
args.Add(ParseArg(a));
// — Parse return (may be empty) —
ArgInfo? ret = null;
if (dict.TryGetValue("return", out var retRaw) && retRaw.AsGodotDictionary() is Dictionary rd && rd.Count > 0)
ret = ParseArg(rd);
list.Add(new MethodInfoEx(
Name: (string)dict["name"],
Args: args,
DefaultArgs: (Array)dict["default_args"],
Flags: (MethodFlags)(int)dict["flags"],
Id: (int)dict["id"],
ReturnValue: ret
));
}
return list;
}
public static bool TryGetMethodInfo(this GodotObject godotObject, string property, out MethodInfoEx info){
foreach (var item in GetMethods(godotObject))
{
if (item.Name == property){
info = item;
return true;
}
}
info = default;
return false;
}
public static List<PropertyInfoEx> GetPropertyListEx(this GodotObject godotObject)=>GetProperties(godotObject);
public static List<PropertyInfoEx> GetProperties(GodotObject obj)
{
var raw = obj.GetPropertyList();
var list = new List<PropertyInfoEx>(raw.Count);
foreach (Dictionary dict in raw)
{
list.Add(new PropertyInfoEx(
Name: (string)dict["name"],
ClassName: (string)dict["class_name"],
Type: (Variant.Type)(int)dict["type"],
Hint: (PropertyHint)(int)dict["hint"],
HintString: (string)dict["hint_string"],
Usage: (PropertyUsageFlags)(int)dict["usage"]
));
}
return list;
}
public static PropertyInfoEx GetProperty(this IEnumerable<PropertyInfoEx> properties, string name)=>properties.FirstOrDefault(item=>item.Name == name);
public static bool TryGetPropertyInfo(this GodotObject godotObject, string property, out PropertyInfoEx info){
foreach (var item in GetProperties(godotObject))
{
if (item.Name == property){
info = item;
return true;
}
}
info = default;
return false;
}
/* ──────────── Internals ──────────── */
private static ArgInfo ParseArg(Dictionary d) => new(
Name: (string)d["name"],
Type: (Variant.Type)(int)d["type"],
Hint: (PropertyHint)(int)d["hint"],
HintString: (string)d["hint_string"],
DefaultValue: d.TryGetValue("default_value", out var dv) ? dv : default);
}

View File

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

View File

@@ -1,77 +0,0 @@
using System;
using System.Collections.Generic;
using Godot;
using Godot.Collections;
namespace SJK.GodotHelpers;
public static class VariantUtils
{
public static Variant SafeToVariant(object value)
{
return value switch
{
null => new Variant(),
bool b => Variant.From(b),
int i => Variant.From(i),
long l => Variant.From((int)l), // Godot Variant only supports 32-bit int
float f => Variant.From(f),
double d => Variant.From((float)d),
string s => Variant.From(s),
Vector2 v2 => Variant.From(v2),
Vector2I v2i => Variant.From(v2i),
Vector3 v3 => Variant.From(v3),
Vector3I v3i => Variant.From(v3i),
Vector4 v4 => Variant.From(v4),
Vector4I v4i => Variant.From(v4i),
Rect2 rect2 => Variant.From(rect2),
Rect2I rect2i => Variant.From(rect2i),
Quaternion q => Variant.From(q),
Basis basis => Variant.From(basis),
Transform2D t2d => Variant.From(t2d),
Transform3D t3d => Variant.From(t3d),
Color color => Variant.From(color),
Plane plane => Variant.From(plane),
Aabb aabb => Variant.From(aabb),
GodotObject go => Variant.From(go),
byte[] bytes => Variant.From(bytes),
StringName sn => Variant.From(sn),
NodePath np => Variant.From(np),
Callable call => Variant.From(call),
Signal sig => Variant.From(sig),
Dictionary dict => Variant.From(dict),
Godot.Collections.Array array => Variant.From(array),
_ => throw new InvalidCastException($"Unsupported type '{value?.GetType().FullName}' for Variant conversion.")
};
}
public static Type GetSystemType(this Variant.Type type) => type switch
{
Variant.Type.Nil => typeof(object),
Variant.Type.Bool => typeof(bool),
Variant.Type.Int => typeof(int),
Variant.Type.Float => typeof(float),
Variant.Type.String => typeof(string),
Variant.Type.Vector2 => typeof(Vector2),
Variant.Type.Vector2I => typeof(Vector2I),
Variant.Type.Rect2 => typeof(Rect2),
Variant.Type.Rect2I => typeof(Rect2I),
Variant.Type.Vector3 => typeof(Vector3),
Variant.Type.Vector3I => typeof(Vector3I),
Variant.Type.Vector4 => typeof(Vector4),
Variant.Type.Vector4I => typeof(Vector4I),
Variant.Type.Transform2D => typeof(Transform2D),
Variant.Type.Transform3D => typeof(Transform3D),
Variant.Type.Basis => typeof(Basis),
Variant.Type.Quaternion => typeof(Quaternion),
Variant.Type.Aabb => typeof(Aabb),
Variant.Type.Color => typeof(Color),
Variant.Type.Plane => typeof(Plane),
Variant.Type.StringName => typeof(StringName),
Variant.Type.NodePath => typeof(NodePath),
Variant.Type.Rid => typeof(Rid),
Variant.Type.Object => typeof(GodotObject),
Variant.Type.Callable => typeof(Callable),
Variant.Type.Signal => typeof(Signal),
Variant.Type.Dictionary => typeof(Godot.Collections.Dictionary),
Variant.Type.Array => typeof(Godot.Collections.Array),
_ => typeof(object)
};
}

View File

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

View File

@@ -12,7 +12,8 @@ using SJK.Functional;
[Tool]
[Meta(typeof(IAutoNode))]
public partial class BeltPort : Node3D, IBeltPort {
public partial class BeltPort : Node3D, IBeltPort
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IVoxelGridRegistry Grid => this.DependOn<IVoxelGridRegistry>();
[Export] public Direction Face { get; set; } = default!;
@@ -21,7 +22,7 @@ public partial class BeltPort : Node3D, IBeltPort {
[Export] public Path3D Path { get; set; } = default!;
[Dependency] public IItemRenderer ItemRenderer => this.DependOn<IItemRenderer>();
public BeltPortProfile Profile => new(GridTransform3D.FromGodot(GlobalTransform), Width, Access);
[Dependency] public IItemTransferAnimator ItemTransferAnimator => this.DependOn<IItemTransferAnimator>(()=> new CurveItemTransfer(){Curve3D = Path.Curve,Tree = GetTree(), ItemRenderer = ItemRenderer, Transform3D = GlobalTransform});
[Dependency] public IItemTransferAnimator ItemTransferAnimator => this.DependOn<IItemTransferAnimator>(() => new CurveItemTransfer() { Curve3D = Path.Curve, Tree = GetTree(), ItemRenderer = ItemRenderer, Transform3D = GlobalTransform });
public void OnResolved()
{
if (Engine.IsEditorHint())
@@ -33,16 +34,16 @@ public partial class BeltPort : Node3D, IBeltPort {
}
public override void _Process(double delta)
{
DebugDraw3D.DrawLine(GlobalPosition,GlobalTransform * Face.ToVector(), Colors.Red);
DebugDraw3D.DrawLine(GlobalPosition, GlobalTransform * Face.ToVector(), Colors.Red);
if (Engine.IsEditorHint())
{
return;
}
for (int i = 0; i < _itemsDummys.Count; i++)
{
_itemsDummys[i] = (_itemsDummys[i].i+(float)delta,_itemsDummys[i].beltItem);
_itemsDummys[i] = (_itemsDummys[i].i + (float)delta, _itemsDummys[i].beltItem);
GD.Print(_itemsDummys[i].i);
ItemRenderer.UpdateTransform(_itemsDummys[i].beltItem,GlobalTransform * Path.Curve.SampleBakedWithRotation(_itemsDummys[i].i));
ItemRenderer.UpdateTransform(_itemsDummys[i].beltItem, GlobalTransform * Path.Curve.SampleBakedWithRotation(_itemsDummys[i].i));
if (_itemsDummys[i].i > Path.Curve.GetBakedLength())
{
_itemsDummys[i].beltItem.Dispose();
@@ -57,11 +58,11 @@ DebugDraw3D.DrawLine(GlobalPosition,GlobalTransform * Face.ToVector(), Colors.Re
return true;
throw new System.NotImplementedException();
}
List<(float i,IBeltItem beltItem)> _itemsDummys = [];
List<(float i, IBeltItem beltItem)> _itemsDummys = [];
public bool TryInsert(IBeltItem item, LaneSpan laneSpan, float beltT)
{
var tween = ItemTransferAnimator.StartTransfer(new(item,beltT){LaneSpan = laneSpan}, () => GD.Print("Done"));
var tween = ItemTransferAnimator.StartTransfer(new(item, beltT) { LaneSpan = laneSpan }, () => GD.Print("Done"));
// GD.Print("gg "+laneSpan);
tween.TweenCallback(Callable.From(item.Dispose));
// GD.Print(laneSpan);
@@ -103,7 +104,7 @@ public class CurveItemTransfer : IItemTransferAnimator
Curve3D curve,
float duration,
IItemRenderer renderer)
{
{
float length = curve.GetBakedLength();
var tween = Tree.CreateTween();
@@ -111,9 +112,9 @@ public class CurveItemTransfer : IItemTransferAnimator
tween.TweenMethod(
Callable.From<float>(t =>
{
//Transform is not being set when using update transform in a tween, but can set position
//Transform is not being set when using update transform in a tween, but can set position
// renderer.UpdateTransform(item, Transform3D * curve.SampleBakedWithRotation(t),1/duration);
(renderer as TestItemRendered)._items[item.Item].Transform =Transform3D *Curve3D.SampleBakedWithRotation(t).Translated(-Curve3D.SampleBakedWithRotation(t).Basis.X * item.LaneSpan.Start);
(renderer as TestItemRendered)._items[item.Item].Transform = Transform3D * Curve3D.SampleBakedWithRotation(t).Translated(-Curve3D.SampleBakedWithRotation(t).Basis.X * item.LaneSpan.Start);
// GD.PrintS(Transform3D * curve.SampleBakedWithRotation(t).Origin,1/duration,(renderer as TestItemRendered)._items[item].GlobalPosition);
}),
0f,
@@ -121,10 +122,12 @@ public class CurveItemTransfer : IItemTransferAnimator
duration
);
return tween;
}
public Tween StartTransfer(ConveyorSlice item, Action onFinished = null){
var tween = AnimateAlongCurve(item,Curve3D,1,ItemRenderer);
if (onFinished is not null){
}
public Tween StartTransfer(ConveyorSlice item, Action onFinished = null)
{
var tween = AnimateAlongCurve(item, Curve3D, 1, ItemRenderer);
if (onFinished is not null)
{
tween.TweenCallback(Callable.From(onFinished));
}
return tween;

View File

@@ -16,7 +16,7 @@ public partial class ConveyorItemRender : Node
[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!;
private Chickensoft.Sync.Primitives.AutoList<ConveyorSlice>.Binding _binding = default!;
public override async void _Ready()
{
base._Ready();
@@ -24,7 +24,7 @@ public partial class ConveyorItemRender : Node
{
await ToSignal(ItemConveyor, Node.SignalName.Ready);
}
binding = ItemConveyor.Items.Items.Bind();
_binding = ItemConveyor.Items.Items.Bind();
// binding.OnRemove(callback =>
// {
// Items.Remove(callback.Item);
@@ -36,37 +36,14 @@ public partial class ConveyorItemRender : Node
// // node.QueueFree();
// // }
// });
binding.OnAdd((i, v) =>
{
// itemsRenders[i.Item] = new MeshInstance3D(){Mesh = new BoxMesh()};
// AddSibling(itemsRenders[i.Item]);
// itemsRenders[i.Item].Transform = Path3D.Curve.SampleBakedWithRotation(i.BeltT);
// GD.Print($"Item : {i},{v} added");
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)));
return;
if (itemsRenders.TryGetValue(a.Item, out var node))
{
if (tweens.TryGetValue(a.Item, out var t))
{
t.Kill();
}
tweens[a.Item] = t = CreateTween();
t.TweenProperty(node, "transform",Path3D.Curve.SampleBakedWithRotation(b.BeltT), .25f);
// node.Transform = Path3D.Curve.SampleBakedWithRotation(b.BeltT);
}
});
_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)));
}
private Dictionary<IBeltItem, Node3D> itemsRenders = [];//This would be an item server for reuse via depency
private Dictionary<IBeltItem, Tween> tweens = [];//This would be an item server for reuse via depency
protected override void Dispose(bool disposing)
{
binding.Dispose();
_binding.Dispose();
base.Dispose(disposing);
}
}
@@ -84,18 +61,20 @@ public partial class TestItemRendered : Node3D, IItemRenderer
private ConditionalWeakTable<IBeltItem, Tween> _tweens = [];
public void Remove(IBeltItem beltItem)
{
if (_items.TryGetValue(beltItem, out var node)){
if (_items.TryGetValue(beltItem, out var node))
{
node.QueueFree();
}
_items.Remove(beltItem);
}
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time ){
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time)
{
if (!_items.TryGetValue(beltItem, out var node))
{
_items.Add(beltItem,node = beltItem.CreateItemVisual());
_items.Add(beltItem, node = beltItem.CreateItemVisual());
AddChild(node);
beltItem.Disposed += _ =>{node.QueueFree();_items.Remove(beltItem);};
beltItem.Disposed += _ => { node.QueueFree(); _items.Remove(beltItem); };
node.Transform = newTransform;
return;
}
@@ -107,8 +86,8 @@ public partial class TestItemRendered : Node3D, IItemRenderer
// GD.Print(newTransform);
tween = GetTree().CreateTween().BindNode(node);
tween.TweenProperty(node, "transform", newTransform, time);
_tweens.Add(beltItem,tween);
_tweens.Add(beltItem, tween);
}
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform) => UpdateTransform(beltItem,newTransform,.25f);
public void UpdateTransform(IBeltItem beltItem, Transform3D newTransform) => UpdateTransform(beltItem, newTransform, .25f);
}

View File

@@ -34,7 +34,7 @@ public class Sorted1DList<T>
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])})");
$"AutoList not sorted at index {i - 1} → {i}. ({_getPosition(_items[i - 1])},{_getPosition(_items[i])})");
}
}
});
@@ -49,7 +49,7 @@ public class Sorted1DList<T>
{
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++)
for (int i = Mathf.Max(0, startIndex ?? 0); i < _items.Count; i++)
{
bool removed = false;
yield return new(_items[i],
@@ -81,7 +81,7 @@ public class Sorted1DList<T>
{
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--)
for (int i = Math.Min(startIndex ?? (_items.Count - 1), _items.Count - 1); i >= 0; i--)
{
bool removed = false;
yield return new(_items[i],
@@ -102,11 +102,11 @@ public class Sorted1DList<T>
throw new NotSupportedException("Can not Replace an Item after Removing it");
}
if (i-1>=0 && _getPosition(_items[i-1]) >= _getPosition(replaced))
if (i - 1 >= 0 && _getPosition(_items[i - 1]) >= _getPosition(replaced))
{
throw new Exception();
}
if (i+1<Count && _getPosition(_items[i+1]) <= _getPosition(replaced))
if (i + 1 < Count && _getPosition(_items[i + 1]) <= _getPosition(replaced))
{
throw new Exception();
}
@@ -123,7 +123,7 @@ public class Sorted1DList<T>
_items.Add(item);
return;
}
if (pos <=_getPosition(_items[0]))
if (pos <= _getPosition(_items[0]))
{
_items.Insert(0, item);
return;
@@ -176,7 +176,8 @@ public class Sorted1DList<T>
public void Replace(T slice) => _replace(slice);
}
}
[Meta(typeof(IAutoNode))][Tool]
[Meta(typeof(IAutoNode))]
[Tool]
public partial class TestItemConveyor : Node, IMovementConveyor
{
public override void _Notification(int what) => this.Notify(what);
@@ -302,7 +303,7 @@ public partial class TestItemConveyor : Node, IMovementConveyor
var points = item.Points();
GridRegistry.Register(item, [.. points]);
}
StartPort.TryInsert(new TestItem(), LaneSpan.Shifted(LaneSpan.One,0), 0);
StartPort.TryInsert(new TestItem(), LaneSpan.Shifted(LaneSpan.One, 0), 0);
// StartPort.TryInsert(new TestItem(), LaneSpan.Sh fted(LaneSpan.One,1), 0);
// Items.Insert(new ConveyorSlice(new TestItem(), 0));
// _items.Add(new (new TestItem()));
@@ -404,7 +405,7 @@ public partial class TestItemConveyor : Node, IMovementConveyor
var mappedLane2 = MapLaneOrFail(port, otherport, laneSpan);
if (mappedLane2.HasValue(out var lane2))
{
return new PortBeltObstacle(distanceToBoundary,lane2,otherport);
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
}
@@ -523,10 +524,10 @@ public partial class TestItemConveyor : Node, IMovementConveyor
return new LaneSpan((ushort)newStart, (ushort)newEnd).ToOption();
}
private ItemConveyor.BeltDirection DirectionAwayFromEnd(ItemConveyor.ConveyorEnd conveyorEnd) => conveyorEnd switch {ItemConveyor.ConveyorEnd.Start=>ItemConveyor.BeltDirection.TowardEnd,ItemConveyor.ConveyorEnd.End=>ItemConveyor.BeltDirection.TowardStart};
private ItemConveyor.BeltDirection DirectionAwayFromEnd(ItemConveyor.ConveyorEnd conveyorEnd) => conveyorEnd switch { ItemConveyor.ConveyorEnd.Start => ItemConveyor.BeltDirection.TowardEnd, ItemConveyor.ConveyorEnd.End => ItemConveyor.BeltDirection.TowardStart };
public IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardEnd() => Items.EnumerateTowardEnd();
public IEnumerable<Sorted1DList<ConveyorSlice>.ItemHandle> EnumerateTowardStart() => Items.EnumerateTowardStart();
private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), new(.5f, -.5f, -.5f), new(-.5f, -.5f, -.5f), new(-.5f, .5f, -.5f)];
private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), new(.5f, -.5f, -.5f), new(-.5f, -.5f, -.5f), new(-.5f, .5f, -.5f)];
public override void _Process(double delta)
{
@@ -538,7 +539,7 @@ private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), n
{
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.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);
@@ -559,16 +560,13 @@ private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), n
}
else if (beltT is ItemConveyor.BeltTOffset endOffset)
{
return HasClearance(endOffset.T,lane);
return HasClearance(endOffset.T, lane);
// var lowerObstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardStart, endOffset.T, ItemConveyor.ITEMSIZE,LaneSpan.One);
// var upperObstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, endOffset.T, ItemConveyor.ITEMSIZE,LaneSpan.One);
// var lowerDistanceAllowed = lowerObstacle.DistanceToCenter - (lowerObstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// var upperObstacleAllowed = upperObstacle.DistanceToCenter - (upperObstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// return ItemConveyor.ITEMSIZE < lowerDistanceAllowed && ItemConveyor.ITEMSIZE < upperObstacleAllowed;
}
// return true;
throw new NotImplementedException();
}
// if (beltT is ItemConveyor.BeltTEnd end && end.End == ItemConveyor.ConveyorEnd.End){
@@ -584,12 +582,12 @@ private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), n
{
if (end.End == ItemConveyor.ConveyorEnd.End)
{
Items.Insert(new (item, Length-offset){LaneSpan = laneSpan});
Items.Insert(new(item, Length - offset) { LaneSpan = laneSpan });
// _items.Add(new(item, Length-offset));
}
else
{
Items.Insert(new (item, offset) {LaneSpan = laneSpan});
Items.Insert(new(item, offset) { LaneSpan = laneSpan });
// _items.Insert(0, new(item, offset));
}
return true;
@@ -602,7 +600,7 @@ private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), n
return false;
}
Items.Insert(new (item, endOffset.T){LaneSpan = laneSpan});
Items.Insert(new(item, endOffset.T) { LaneSpan = laneSpan });
// int insertIndex = FindInsertIndex(endOffset.T);
// _items.Insert(insertIndex, new(item, endOffset.T));
@@ -650,26 +648,26 @@ private static Vector3[] _Square = [new(-.5f, .5f, -.5f), new(.5f, .5f, -.5f), n
}
}
// Items.Add(new ConveyorSlice(new TestItem(), 0));
// StartPort = new ConveyorPort(this,
// new BeltPortProfile(Position, Direction.Back, 1, PortAccess.BiDirectional),
// new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.Start),
// (item, offset) =>
// {
// var obstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, 0, offset, LaneSpan.One);
// return ItemConveyor.ITEMSIZE < obstacle.DistanceToCenter - (obstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// },
// (item, offset) => { _items.Insert(0, new(item, offset)); return true;});
// EndPort = new ConveyorPort(this,
// new BeltPortProfile(Position, Direction.Front, 1, PortAccess.BiDirectional),
// new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.End),
// (item, offset) =>
// {
// var obstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, Length, offset, LaneSpan.One);
// return ItemConveyor.ITEMSIZE < obstacle.DistanceToCenter - (obstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// // return ItemConveyor.ITEMSIZE < GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardStart, Length, SpeedMagnitude, LaneSpan.One);
// },
// (item, offset) => { _items.Add(new(item, offset)); return true;});
// Items.Add(new ConveyorSlice(new TestItem(), 0));
// StartPort = new ConveyorPort(this,
// new BeltPortProfile(Position, Direction.Back, 1, PortAccess.BiDirectional),
// new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.Start),
// (item, offset) =>
// {
// var obstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, 0, offset, LaneSpan.One);
// return ItemConveyor.ITEMSIZE < obstacle.DistanceToCenter - (obstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// },
// (item, offset) => { _items.Insert(0, new(item, offset)); return true;});
// EndPort = new ConveyorPort(this,
// new BeltPortProfile(Position, Direction.Front, 1, PortAccess.BiDirectional),
// new ItemConveyor.BeltTEnd(ItemConveyor.ConveyorEnd.End),
// (item, offset) =>
// {
// var obstacle = GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardEnd, Length, offset, LaneSpan.One);
// return ItemConveyor.ITEMSIZE < obstacle.DistanceToCenter - (obstacle.IsItem ? ItemConveyor.ITEMSIZE : 0);
// // return ItemConveyor.ITEMSIZE < GetDistanceToNextItem(ItemConveyor.BeltDirection.TowardStart, Length, SpeedMagnitude, LaneSpan.One);
// },
// (item, offset) => { _items.Add(new(item, offset)); return true;});
//TODO Should liklely account for max search distance where the conveyorm may be needed to know
public record class BeltObstacle(float Distance)
{

View File

@@ -23,7 +23,6 @@ public partial class VoxelGridNode : Node3D, IProvide<IVoxelGridQuery<LayeredEqu
IItemRenderer IProvide<IItemRenderer>.Value() => _itemRenderer;
public override void _Ready()
{
TestStructural.Test();
GD.Print();
base._Ready();
_voxelGrid = new EquipmentVoxelGrid();
@@ -107,7 +106,8 @@ public class LayeredEquipment
}
}
}
public sealed class SlotDescriptor {
public sealed class SlotDescriptor
{
public SlotDirection Direction { get; }
public SlotDescriptor(
@@ -117,10 +117,12 @@ public sealed class SlotDescriptor {
Direction = direction;
}
}
public abstract class SlotLogic<TPayload> {
public abstract class SlotLogic<TPayload>
{
public SlotDescriptor Descriptor { get; }
protected SlotLogic(SlotDescriptor descriptor) {
protected SlotLogic(SlotDescriptor descriptor)
{
Descriptor = descriptor;
}
@@ -133,26 +135,30 @@ public abstract class SlotLogic<TPayload> {
);
}
public sealed class ItemSlotLogic
: SlotLogic<IBeltItem> {
: SlotLogic<IBeltItem>
{
public ItemSlotLogic(SlotDescriptor descriptor)
: base(descriptor) {}
: base(descriptor) { }
public override bool CanTransfer(IBeltItem item) => false;
// item.Count > 0;
public override bool TryTransfer(IBeltItem item) {
public override bool TryTransfer(IBeltItem item)
{
// routing rules
return true;
}
}
[Meta]
public partial class ItemSlotNode
: SlotComponentNode {
: SlotComponentNode
{
private ItemSlotLogic _logic;
public override void _Ready() {
public override void _Ready()
{
base._Ready();
_logic = new ItemSlotLogic(
new SlotDescriptor(Direction)
@@ -163,7 +169,8 @@ public partial class ItemSlotNode
}
public void Tick(IBeltItem stack) {
public void Tick(IBeltItem stack)
{
if (_logic.CanTransfer(stack))
_logic.TryTransfer(stack);
}