diff --git a/ChickenGameTest.csproj b/ChickenGameTest.csproj
index e44b789..c3fe914 100644
--- a/ChickenGameTest.csproj
+++ b/ChickenGameTest.csproj
@@ -37,33 +37,36 @@
+
+
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
diff --git a/assets b/assets
index b5ad429..37af2de 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit b5ad429c59af10bc190d5a2d09c3790a8f4c3620
+Subproject commit 37af2de43458380ee7e86f3635c40bde9ec7093f
diff --git a/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.cs b/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.cs
index 80ed328..9b96600 100644
--- a/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.cs
+++ b/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.cs
@@ -1,8 +1,8 @@
+using System.Diagnostics;
using ChickenGameTest;
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
-using System;
[Meta(typeof(IAutoNode))]
public partial class ConveyorBeltStraight : Node3D, IProvide
{
@@ -16,19 +16,21 @@ public partial class ConveyorBeltStraight : Node3D, IProvide
get => GridTransform3D.FromGodot(GlobalTransform);
set => GlobalTransform = value.ToGodot();
}
+ [Node("ConveyorLogic")]
+ public TestItemConveyor ConveyorLogic { get; set; } = default!;
public override void _Ready()
{
- var node = GetNode("Node") as TestItemConveyor;
base._Ready();
+ Debug.Assert(ConveyorLogic is not null, $"{nameof(ConveyorLogic)} is not set on {nameof(ConveyorBeltStraight)}, Path {SceneFilePath}");
// GD.PrintS(VoxelTransform.Origin,VoxelTransform.Forward);
- node.StartPort = node.CreatePort(
+ ConveyorLogic.StartPort = ConveyorLogic.CreatePort(
new(VoxelTransform.TranslatedLocal(new(1 - Width, 0, 0)).RotateY(2),
// Direction.Back,
Width,
PortAccess.BiDirectional),
new BeltTEnd(ConveyorEnd.Start),
new LaneSpan(0, 1));
- node.EndPort = node.CreatePort(
+ ConveyorLogic.EndPort = ConveyorLogic.CreatePort(
new(VoxelTransform, //new(GridTransform3D.FromGodot(Transform.TranslatedLocal(Vector3.Left)),
// Direction.Front,
Width,
@@ -36,22 +38,23 @@ public partial class ConveyorBeltStraight : Node3D, IProvide
new BeltTEnd(ConveyorEnd.End),
new LaneSpan(0, 1));
- node.OtherPorts = [
- node.CreatePort(
+ ConveyorLogic.OtherPorts = [
+ ConveyorLogic.CreatePort(
new(VoxelTransform.RotateY90CW(),
// Direction.Right,
1,
PortAccess.In),
- new BeltTOffset(node.Length/2),
+ new BeltTOffset(ConveyorLogic.Length/2),
LaneSpan.One),
- node.CreatePort(
+ ConveyorLogic.CreatePort(
new(VoxelTransform.RotateY90CCW(),
// Direction.Left,
1,
PortAccess.In),
- new BeltTOffset(node.Length/2),
+ new BeltTOffset(ConveyorLogic.Length/2),
LaneSpan.One)
];
+
}
public void OnResolved()
{
diff --git a/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn b/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn
index 32a8f1b..4690c42 100644
--- a/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn
+++ b/src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=7 format=3 uid="uid://c4h7mwnfrdesg"]
+[gd_scene format=3 uid="uid://c4h7mwnfrdesg"]
[ext_resource type="Script" uid="uid://dgyuh6un1qoj4" path="res://src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.cs" id="1_mn8ro"]
[ext_resource type="Script" uid="uid://j24fuotdwwx4" path="res://src/VoxelGrid/TestItemConveyor.cs" id="2_1vr1d"]
@@ -13,22 +13,23 @@ _data = {
}
point_count = 2
-[node name="ConveyorBeltStraight" type="Node3D"]
+[node name="ConveyorBeltStraight" type="Node3D" unique_id=1032197109]
script = ExtResource("1_mn8ro")
+Width = 1
-[node name="Node" type="Node" parent="."]
+[node name="ConveyorLogic" type="Node" parent="." unique_id=1693852977]
script = ExtResource("2_1vr1d")
-[node name="conveyor-sides" parent="." instance=ExtResource("2_mn8ro")]
+[node name="conveyor-sides" parent="." unique_id=516239399 instance=ExtResource("2_mn8ro")]
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 0)
-[node name="arrow-basic2" parent="." instance=ExtResource("3_1vr1d")]
+[node name="arrow-basic2" parent="." unique_id=1668302786 instance=ExtResource("3_1vr1d")]
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0.21879572, 0)
-[node name="Path3D" type="Path3D" parent="."]
+[node name="Path3D" type="Path3D" parent="." unique_id=878303794]
curve = SubResource("Curve3D_x5qdr")
-[node name="Node2" type="Node" parent="." node_paths=PackedStringArray("Path3D", "ItemConveyor")]
+[node name="Node2" type="Node" parent="." unique_id=1875202216 node_paths=PackedStringArray("Path3D", "ItemConveyor")]
script = ExtResource("4_g7n1f")
Path3D = NodePath("../Path3D")
-ItemConveyor = NodePath("../Node")
+ItemConveyor = NodePath("../ConveyorLogic")
diff --git a/src/Items/Components/Tag.cs b/src/Items/Components/Tag.cs
new file mode 100644
index 0000000..79a73f3
--- /dev/null
+++ b/src/Items/Components/Tag.cs
@@ -0,0 +1,30 @@
+namespace FoodFactory.Items;
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+
+public readonly struct Tag : IEquatable, IEqualityOperators, IComparisonOperators,
+ IComparable
+{
+ public readonly string Name => TagRegistry.GetName(this);
+ internal readonly int _id;
+
+ internal Tag(int id)
+ {
+ Debug.Assert(id >= 0);
+ _id = id;
+ }
+ public override bool Equals([NotNullWhen(true)] object? obj) => obj is Tag tag && Equals(tag);
+ public bool Equals(Tag other) => _id == other._id;
+ public override int GetHashCode() => _id;
+ public override string ToString() => Name;
+ public int CompareTo(Tag other) => _id.CompareTo(other._id);
+ public static bool operator >(Tag left, Tag right) => left._id > right._id;
+ public static bool operator >=(Tag left, Tag right) => left._id >= right._id;
+ public static bool operator <(Tag left, Tag right) => left._id < right._id;
+ public static bool operator <=(Tag left, Tag right) => left._id <= right._id;
+ public static bool operator ==(Tag left, Tag right) => left._id == right._id;
+ public static bool operator !=(Tag left, Tag right) => left._id != right._id;
+}
diff --git a/src/Items/Components/Tag.cs.uid b/src/Items/Components/Tag.cs.uid
new file mode 100644
index 0000000..8581907
--- /dev/null
+++ b/src/Items/Components/Tag.cs.uid
@@ -0,0 +1 @@
+uid://1o2e2wou367m
diff --git a/src/Items/Components/Tags.cs b/src/Items/Components/Tags.cs
index 362773a..753d84b 100644
--- a/src/Items/Components/Tags.cs
+++ b/src/Items/Components/Tags.cs
@@ -2,13 +2,9 @@ namespace FoodFactory.Items;
using System;
using System.Collections;
-using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
-using System.Numerics;
-using System.Threading;
public readonly struct Tags : IEquatable, IReadOnlyCollection
{
@@ -178,30 +174,6 @@ public readonly struct Tags : IEquatable, IReadOnlyCollection
}
}
-public readonly struct Tag : IEquatable, IEqualityOperators, IComparisonOperators,
- IComparable
-{
- public readonly string Name => TagRegistry.GetName(this);
- internal readonly int _id;
-
- internal Tag(int id)
- {
- Debug.Assert(id >= 0);
- _id = id;
- }
- public override bool Equals([NotNullWhen(true)] object? obj) => obj is Tag tag && Equals(tag);
- public bool Equals(Tag other) => _id == other._id;
- public override int GetHashCode() => _id;
- public override string ToString() => Name;
- public int CompareTo(Tag other) => _id.CompareTo(other._id);
- public static bool operator >(Tag left, Tag right) => left._id > right._id;
- public static bool operator >=(Tag left, Tag right) => left._id >= right._id;
- public static bool operator <(Tag left, Tag right) => left._id < right._id;
- public static bool operator <=(Tag left, Tag right) => left._id <= right._id;
- public static bool operator ==(Tag left, Tag right) => left._id == right._id;
- public static bool operator !=(Tag left, Tag right) => left._id != right._id;
-}
-
public static class TagRegistry
{
private static Registry _registry = new();
diff --git a/src/Items/Components/Tags.cs.uid b/src/Items/Components/Tags.cs.uid
new file mode 100644
index 0000000..cec5c02
--- /dev/null
+++ b/src/Items/Components/Tags.cs.uid
@@ -0,0 +1 @@
+uid://chk03ru27wxw1
diff --git a/src/Items/Item.cs b/src/Items/Item.cs
index e6b7a99..6e395a0 100644
--- a/src/Items/Item.cs
+++ b/src/Items/Item.cs
@@ -2,8 +2,12 @@ namespace ChickenGameTest;
using System;
using System.Collections.Generic;
-using System.Runtime.CompilerServices;
+using System.Linq;
+using Arch.Core;
+using Arch.Core.Extensions;
+using FoodFactory.Items;
using Godot;
+using SJK.Functional;
///
/// Items that can be on a belt
@@ -16,15 +20,46 @@ public interface IBeltItem : IDisposable
delegate void ItemRemoved(IBeltItem item);
event ItemRemoved? Disposed;
}
-
-public class TestItem() : IBeltItem
+public interface IBeltItemData
+{
+ T GetItem();
+}
+public class TestItem() : IBeltItem, IBeltItemData
{
- public float Temp { get; set; }
public int Width { get; set; }
public int Height { get; set; }
+ public static PackedScene PotatoScene = ResourceLoader.Load("res://assets/KayKit_Restaurant_Bits_1.0_FREE/Assets/gltf/food_ingredient_potato.gltf");
+ public static PackedScene OnionScene = ResourceLoader.Load("res://assets/KayKit_Restaurant_Bits_1.0_FREE/Assets/gltf/food_ingredient_onion.gltf");
+ public static PackedScene ChoppedOnionScene = ResourceLoader.Load("res://assets/KayKit_Restaurant_Bits_1.0_FREE/Assets/gltf/food_ingredient_onion_chopped.gltf");
+ public Node3D CreateItemVisual()
+ {
+ Node3D node;
+ if (Item.Get().Contains(TagRegistry.GetTag("potato")))
+ {
+ node = PotatoScene.Instantiate();
+ }
+ else if (Item.Get().ContainsAny(new Tags("sliced")))
+ {
+ node = ChoppedOnionScene.Instantiate();
+ }
+ else if (Item.Get().Contains(TagRegistry.GetTag("onion")))
+ {
+ node = OnionScene.Instantiate();
+ }
+ else
+ {
+ node = new MeshInstance3D() { Mesh = new BoxMesh() };
+ }
+ node.GetChildren().OfType().ToList().ForEach(i => i.Scale *= new Vector3(.2f, .2f, .2f));
+ if (Item.TryGet(out var color))
+ {
+ node.GetChildren().OfType().FirstOrNone().IfSome(some => some.SetSurfaceOverrideMaterial(0, new StandardMaterial3D() { AlbedoColor = Item.TryGet(out var color) ? color : Colors.White }));
+ }
+ return node;
+ // return new MeshInstance3D() { Mesh = new BoxMesh() { Size = new(.1f, .1f, .1f) }, MaterialOverride = new StandardMaterial3D() { AlbedoColor = Item.TryGet(out var color) ? color : Colors.White } };
+ }
- public Node3D CreateItemVisual() => new MeshInstance3D() { Mesh = new BoxMesh() { Size = new(.1f, .1f, .1f) } };
private bool _disposed;
public event IBeltItem.ItemRemoved? Disposed;
@@ -40,7 +75,10 @@ public class TestItem() : IBeltItem
_disposed = true;
Disposed?.Invoke(this);
}
- public Dictionary PlaceHolderData = [];
+
+ public Entity GetItem() => Item;
+
+ public Entity Item;
}
public interface IFluidItem
diff --git a/src/Items/ItemECSTest.cs b/src/Items/ItemECSTest.cs
index b85428a..5977aed 100644
--- a/src/Items/ItemECSTest.cs
+++ b/src/Items/ItemECSTest.cs
@@ -2,10 +2,9 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using Arch.Core;
using Arch.Core.Extensions;
-using Arch.LowLevel.Jagged;
+using Arch.LowLevel;
using FoodFactory;
using FoodFactory.Items;
using FoodFactory.Recipes;
@@ -21,8 +20,8 @@ public class Test
var bucket = new BucketStorage>();
- var pizza = world.Create(new Name("Pizza"), new Temperature(5f), new MarcoNutrients(5, 5, 10), new MicroNutrients([new Vitamin("D", 5)]));
- var turkey = world.Create(new Name("Turkey"), new Temperature(5f), new MarcoNutrients(5, 5, 10));
+ var pizza = world.Create(new Name("Pizza"), new Temperature(5f), new MarcoNutrients(5, 5, new()), new MicroNutrients([new Vitamin("D", 5)]));
+ var turkey = world.Create(new Name("Turkey"), new Temperature(5f), new MarcoNutrients(5, 5, new()));
// var componentType = new ComponentType(ComponentRegistry.Size-1, 8);
// ComponentRegistry.Add(typeof(LayeredStack2), componentType);
@@ -37,7 +36,7 @@ public class Test
pizza.Get().Kelvin += .1f;
}
pizza.Add(new IngredientOf(turkey));
- var a = new List(){pizza};
+ var a = new List() { pizza };
turkey.Add(new LayeredStack(bucket.Add(a)));
turkey.Add(new LayeredStack2(a));
@@ -70,36 +69,6 @@ public class Test
}
}
);
- var recipes = new Recipes();
-
- var item = recipes.TESTBlueprint.Factory(new BlueprintContext(){World = world, BluePrintId = new BlueprintId(recipes.TESTBlueprint)});//world.Create(new Name("Potato_Raw"), new Temperature(71f), new Tags("raw", "potato", "vegetable"));
- Span items = [item];
- var context = new RecipeContext(world, items);
- var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
- // var recipe = new PotatoCookRecipe();
- var recipe = recipes.GetRecipes(new RecipeAction("cook"), 1, [item.Get()], [])[0].Recipe;
- if (recipe.CanProcess(context))
- {
- var result = recipe.Process(context, ref builder);
- var list3 = new List();
- for (int i = 0; i < result.CreateLength; i++)
- {
- list3.Add(result.Create[i](in context));
- }
- if (result.RemoveLength > 0)
- {
- for (int i = 0; i < result.RemoveLength; i++)
- {
- GD.Print(result.Remove[i]);
- if (result.Remove[i])
- {
- world.Destroy(items[i]);
- }
- }
- }
- GD.Print(string.Join(',',list3[0].GetAllComponents()));
- GD.Print(items[0].IsAlive());
- }
}
}
@@ -109,15 +78,64 @@ internal interface IEntityContainer
}
public record struct Name(string Value);
-public record struct MarcoNutrients(float Fat, float Protein, float Carbohydrate);
+public record struct BurnableTemp(Temperature Temperature);
+public record struct BurnedItem(Temperature BurnedAt, string Description);//Info about how burnted item is
+public record struct MarcoNutrients(Weight Fat, Weight Protein, Carbohydrates Carbohydrate);
+public readonly record struct Carbohydrates(
+ Weight Fiber,
+ Weight Starch,
+ SugarProfile Sugars
+)
+{
+ public Weight TotalWeight =>
+ Fiber + Starch + Sugars.TotalWeight;
+
+ public double Calories =>
+ (Fiber.Grams * 2.0) +
+ (Starch.Grams * 4.0) +
+ Sugars.Calories;
+
+ public double Sweetness =>
+ Sugars.Sweetness;
+}
+public readonly record struct SugarProfile(
+ Weight Glucose,
+ Weight Fructose,
+ Weight Sucrose,
+ Weight Lactose
+)
+{
+ public Weight TotalWeight =>
+ Glucose + Fructose + Sucrose + Lactose;
+
+ public double Calories =>
+ TotalWeight.Grams * 4.0;
+
+ public double Sweetness =>
+ (Glucose.Grams * 0.7) +
+ (Fructose.Grams * 1.7) +
+ (Sucrose.Grams * 1.0) +
+ (Lactose.Grams * 0.2);
+
+ public static SugarProfile operator +(
+ SugarProfile a,
+ SugarProfile b) => new(
+ a.Glucose + b.Glucose,
+ a.Fructose + b.Fructose,
+ a.Sucrose + b.Sucrose,
+ a.Lactose + b.Lactose);
+}
+public record struct Mass(Weight Value);// Repsenets the apomix weight of an item, should have things like nutrients allready accounted.
public record struct MicroNutrients(List Vitamins);
-public record struct Vitamin(string Id, float Amount);
-
+public record struct Vitamin(string Id, Weight Amount);
+public record struct Scale(float Value);
public record struct IngredientOf(Entity Source);
public record struct LayeredStack(Handle Handle);
public record struct LayeredStack2(List Children);
+public record struct Bacteria(Handle> Data);
+public record struct BacteriaData(string Name, double Count);
public record struct Handle(int Index, int Version);
@@ -157,7 +175,7 @@ public class BucketStorage
Version = 1,
Occupied = true
};
- Array.Resize(ref _slots, _slots.Length + 1);
+ System.Array.Resize(ref _slots, _slots.Length + 1);
_slots[^1] = slot;
return new Handle
diff --git a/src/Items/ItemECSTest.cs.uid b/src/Items/ItemECSTest.cs.uid
new file mode 100644
index 0000000..37710a9
--- /dev/null
+++ b/src/Items/ItemECSTest.cs.uid
@@ -0,0 +1 @@
+uid://c5ik7ke6rrlmn
diff --git a/src/Math/Ordered1DList.cs b/src/Math/Ordered1DList.cs
new file mode 100644
index 0000000..4d250e0
--- /dev/null
+++ b/src/Math/Ordered1DList.cs
@@ -0,0 +1,109 @@
+namespace SJK.Math;
+
+using System;
+using System.Collections.Generic;
+using Arch.LowLevel;
+
+public sealed class Ordered1DList : IDisposable where T : unmanaged
+{
+ private readonly UnsafeList _values;
+ public Ordered1DList(int capacity)
+ {
+ _values = new(capacity);
+ }
+ public record struct Entry(float Position, T Value);
+ public void Insert(T item, float position)
+ {
+ if (_values.Count == 0 || position >= _values[^1].Position)
+ {
+ _values.Add(new(position, item));
+ return;
+ }
+ if (position <= _values[0].Position)
+ {
+ _values.Insert(0, new(position, item));
+ return;
+ }
+ var index = LowerBound(position);
+ _values.Insert(index, new(position, item));
+ SortFromIndex(index);
+ }
+ public void RemoveAt(int index) => _values.RemoveAt(index);
+ public void Clear() => _values.Clear();
+ public void MoveAllBy(float offset)
+ {
+ for (int i = 0; i < _values.Count; i++)
+ {
+ _values[i].Position = _values[i].Position + offset;
+ }
+ }
+ private void SortFromIndex(int index)
+ {
+ var entry = _values[index];
+
+ while (index > 0 &&
+ _values[index - 1].Position > entry.Position)
+ {
+ Swap(index, index - 1);
+ index--;
+ }
+
+ // bubble right
+ while (index < _values.Count - 1 &&
+ _values[index + 1].Position < entry.Position)
+ {
+ Swap(index, index + 1);
+ index++;
+ }
+ }
+ private void Swap(int a, int b) => (_values[b], _values[a]) = (_values[a], _values[b]);
+ private int LowerBound(float pos)
+ {
+ int lo = 0;
+ int hi = _values.Count;
+
+ while (lo < hi)
+ {
+ int mid = (lo + hi) >> 1;
+
+ if (_values[mid].Position < pos)
+ {
+ lo = mid + 1;
+ }
+ else
+ {
+ hi = mid;
+ }
+ }
+
+ return lo;
+ }
+ public Enumerator EnumerateTowardEnd(int startIndex) => new(this, towardsEnd: true, startIndex);
+ public Enumerator EnumerateTowardStart(int startIndex) => new(this, towardsEnd: false, startIndex);
+ public ref struct Enumerator
+ {
+ public Enumerator(Ordered1DList list, bool towardsEnd, int index)
+ {
+ _list = list;
+ _towardsEnd = towardsEnd;
+ _index = index;
+ }
+ private readonly Ordered1DList _list;
+ private readonly bool _towardsEnd;
+ private int _index;
+
+ public bool MoveNext()
+ {
+ _index += _towardsEnd ? 1 : -1;
+ return _index >= 0 && _index < _list._values.Count;
+ }
+ public void Remove()
+ {
+ _list._values.RemoveAt(_index);
+ _index -= _towardsEnd ? 1 : -1;
+ }
+
+ public readonly ref Entry Current => ref _list._values[_index];
+ }
+ public void Dispose() => _values.Dispose();
+}
diff --git a/src/Math/Ordered1DList.cs.uid b/src/Math/Ordered1DList.cs.uid
new file mode 100644
index 0000000..c0bac8e
--- /dev/null
+++ b/src/Math/Ordered1DList.cs.uid
@@ -0,0 +1 @@
+uid://uuf56xygihoh
diff --git a/src/Math/Temperature.cs.uid b/src/Math/Temperature.cs.uid
new file mode 100644
index 0000000..c9d09b3
--- /dev/null
+++ b/src/Math/Temperature.cs.uid
@@ -0,0 +1 @@
+uid://pcjdirermsr7
diff --git a/src/Math/Weight.cs b/src/Math/Weight.cs
new file mode 100644
index 0000000..a31fedd
--- /dev/null
+++ b/src/Math/Weight.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Globalization;
+
+public readonly record struct Weight(double Grams)
+ : IComparable,
+ IFormattable
+{
+ // -----------------------------
+ // Metric Constants
+ // -----------------------------
+
+ public const double GRAMS_PER_KILOGRAM = 1000.0;
+ public const double GRAMS_PER_CENTIGRAM = 0.01;
+ public const double GRAMS_PER_MILLIGRAM = 0.001;
+
+ // -----------------------------
+ // Imperial Constants
+ // -----------------------------
+
+ public const double GRAMS_PER_OUNCE = 28.349523125;
+ public const double GRAMS_PER_POUND = 453.59237;
+
+ // -----------------------------
+ // Factory Methods
+ // -----------------------------
+
+ public static Weight FromGrams(double value)
+ => new(value);
+
+ public static Weight FromKilograms(double value)
+ => new(value * GRAMS_PER_KILOGRAM);
+
+ public static Weight FromCentigrams(double value)
+ => new(value * GRAMS_PER_CENTIGRAM);
+
+ public static Weight FromMilligrams(double value)
+ => new(value * GRAMS_PER_MILLIGRAM);
+
+ public static Weight FromOunces(double value)
+ => new(value * GRAMS_PER_OUNCE);
+
+ public static Weight FromPounds(double value)
+ => new(value * GRAMS_PER_POUND);
+
+ // -----------------------------
+ // Unit Properties
+ // -----------------------------
+
+ public double Kilograms => Grams / GRAMS_PER_KILOGRAM;
+ public double Centigrams => Grams / GRAMS_PER_CENTIGRAM;
+ public double Milligrams => Grams / GRAMS_PER_MILLIGRAM;
+
+ public double Ounces => Grams / GRAMS_PER_OUNCE;
+ public double Pounds => Grams / GRAMS_PER_POUND;
+
+ // -----------------------------
+ // Operators
+ // -----------------------------
+
+ public static Weight operator +(Weight a, Weight b)
+ => new(a.Grams + b.Grams);
+
+ public static Weight operator -(Weight a, Weight b)
+ => new(a.Grams - b.Grams);
+
+ public static Weight operator *(Weight a, double scalar)
+ => new(a.Grams * scalar);
+
+ public static Weight operator *(double scalar, Weight a)
+ => new(a.Grams * scalar);
+
+ public static Weight operator /(Weight a, double scalar)
+ => new(a.Grams / scalar);
+
+ // Ratio
+ public static double operator /(Weight a, Weight b)
+ => a.Grams / b.Grams;
+
+ // -----------------------------
+ // Comparisons
+ // -----------------------------
+
+ public int CompareTo(Weight other)
+ => Grams.CompareTo(other.Grams);
+
+ // -----------------------------
+ // Implicit / Explicit Casts
+ // -----------------------------
+
+ // Weight -> double (grams)
+ public static implicit operator double(Weight weight)
+ => weight.Grams;
+
+ // double -> Weight (grams)
+ public static implicit operator Weight(double grams)
+ => new(grams);
+
+ // -----------------------------
+ // Formatting
+ // -----------------------------
+
+ public override string ToString()
+ => ToString("auto", CultureInfo.InvariantCulture);
+
+ public string ToString(string? format, IFormatProvider? provider)
+ {
+ provider ??= CultureInfo.InvariantCulture;
+ format = format?.ToLowerInvariant();
+
+ return format switch
+ {
+ "g" => $"{Grams.ToString("0.##", provider)} g",
+ "kg" => $"{Kilograms.ToString("0.###", provider)} kg",
+ "cg" => $"{Centigrams.ToString("0.##", provider)} cg",
+ "mg" => $"{Milligrams.ToString("0.##", provider)} mg",
+
+ "lb" => $"{Pounds.ToString("0.##", provider)} lb",
+ "oz" => $"{Ounces.ToString("0.##", provider)} oz",
+
+ "auto" or null => AutoFormat(provider),
+
+ _ => throw new FormatException($"Unknown format '{format}'")
+ };
+ }
+
+ private string AutoFormat(IFormatProvider provider)
+ {
+ var abs = Math.Abs(Grams);
+
+ if (abs >= GRAMS_PER_KILOGRAM)
+ {
+ return $"{Kilograms.ToString("0.###", provider)} kg";
+ }
+
+ if (abs < 1.0)
+ {
+ return $"{Milligrams.ToString("0.##", provider)} mg";
+ }
+
+ return $"{Grams.ToString("0.##", provider)} g";
+ }
+
+ // -----------------------------
+ // Common Values
+ // -----------------------------
+
+ public static Weight Zero => new(0);
+}
diff --git a/src/Math/Weight.cs.uid b/src/Math/Weight.cs.uid
new file mode 100644
index 0000000..3359ede
--- /dev/null
+++ b/src/Math/Weight.cs.uid
@@ -0,0 +1 @@
+uid://7e8o324qvsox
diff --git a/src/Recipes/Blueprint.cs b/src/Recipes/Blueprint.cs
new file mode 100644
index 0000000..95afa5f
--- /dev/null
+++ b/src/Recipes/Blueprint.cs
@@ -0,0 +1,58 @@
+namespace FoodFactory.Recipes;
+
+using System;
+using System.Collections.Generic;
+using Arch.Core;
+using ChickenGameTest;
+using FoodFactory.Items;
+
+public interface IBlueprintManger
+{
+ Blueprint GetBlueprint(string name);
+}
+public class BlueprintManger : IBlueprintManger
+{
+ private readonly Dictionary _bluePrints = [];
+ public Blueprint GetBlueprint(string name)
+ {
+ if (!_bluePrints.TryGetValue(name, out var blueprint))
+ {
+ //TODO this is where this should look through mods/base game
+ if (name == "Potato")
+ {
+ blueprint = new Blueprint("Potato", static ctx => ctx.World.Create(new Name("Potato_raw"),
+ new Tags("potato", "raw", "vegetable", "burnable"),
+ new Temperature(40, TemperatureUnit.Fahrenheit),
+ ctx.BluePrintId,
+ new Bacteria(BacterialSystem.Resources.Add([new BacteriaData("slamnala", 400)])),
+ new BurnableTemp(new Temperature(400, TemperatureUnit.Fahrenheit))));//TODO blueprintID should not be passed, but know when blueprint is created, meaning a rework of Blueprint id register
+ }
+ else if (name == "Onion")
+ {
+ blueprint = new Blueprint("Onion", static ctx => ctx.World.Create(new Name("Onion_raw"),
+ new Tags("onion", "raw", "vegetable", "burnable", "sliceable"),
+ new Temperature(71, TemperatureUnit.Fahrenheit),
+ ctx.BluePrintId,
+ new BurnableTemp(new Temperature(400, TemperatureUnit.Fahrenheit)),
+ new Mass(Weight.FromGrams(110)),
+ new Carbohydrates(Fiber: 2, Starch: 3, Sugars: new(Glucose: 0, Fructose: 1.2f, Sucrose: 1, Lactose: 0))
+ ));//TODO blueprintID should not be passed, but know when blueprint is created, meaning a rework of Blueprint id register
+ }
+ else
+ {
+ throw new Exception();
+ }
+ }
+ return blueprint;
+ }
+}
+public record Blueprint(string Name, Func Factory)
+{
+
+}
+
+public struct BlueprintContext
+{
+ public World World;
+ public BlueprintId BluePrintId;
+}
diff --git a/src/Recipes/Blueprint.cs.uid b/src/Recipes/Blueprint.cs.uid
new file mode 100644
index 0000000..fb14a2e
--- /dev/null
+++ b/src/Recipes/Blueprint.cs.uid
@@ -0,0 +1 @@
+uid://cj088ogl8uqmt
diff --git a/src/Recipes/BlueprintId.cs b/src/Recipes/BlueprintId.cs
new file mode 100644
index 0000000..228eb70
--- /dev/null
+++ b/src/Recipes/BlueprintId.cs
@@ -0,0 +1,14 @@
+namespace FoodFactory.Recipes;
+
+using FoodFactory.Items;
+
+public readonly record struct BlueprintId
+{
+ public readonly int Id;
+ public Blueprint Blueprint() => _registry.GetEntry(Id);
+ private static readonly Registry _registry = new();
+ public BlueprintId(Blueprint blueprint)
+ {
+ Id = _registry.GetOrCreate(blueprint);
+ }
+}
diff --git a/src/Recipes/BlueprintId.cs.uid b/src/Recipes/BlueprintId.cs.uid
new file mode 100644
index 0000000..b2c4ea4
--- /dev/null
+++ b/src/Recipes/BlueprintId.cs.uid
@@ -0,0 +1 @@
+uid://b7kmhd6uamhg
diff --git a/src/Recipes/Recipe.cs b/src/Recipes/Recipe.cs
new file mode 100644
index 0000000..56ed2f9
--- /dev/null
+++ b/src/Recipes/Recipe.cs
@@ -0,0 +1,231 @@
+namespace FoodFactory.Recipes;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using Arch.Core;
+using Arch.Core.Extensions;
+using Arch.Core.Extensions.Dangerous;
+using FoodFactory.Items;
+using Godot;
+
+public abstract record Recipe(string Name, BlueprintId[]? BlueprintIds, bool[] RequireAll, Tags[] Inputs, Tags[] Exclude, RecipeOutput RecipeOutput, RecipeAction Action = default, bool InputsOrdered = true)
+{
+ public abstract bool CanProcess(in RecipeContext context);
+ public abstract RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder);
+}
+public readonly record struct RecipeOutput
+{
+ public int? Min { get; }
+ public int? Max { get; }
+ [MemberNotNullWhen(true, nameof(Min), nameof(Max))]
+ public bool IsExact => Min.HasValue && Max.HasValue && Min == Max;
+ [MemberNotNullWhen(true, nameof(Min), nameof(Max))]
+ public bool IsRange => Min.HasValue && Max.HasValue && Min != Max;
+ public bool IsUnbounded => Min == null && Max == null;
+
+ public RecipeOutput(int exact)
+ {
+ Min = exact;
+ Max = exact;
+ }
+
+ public RecipeOutput(int min, int max)
+ {
+ Min = min;
+ Max = max;
+ }
+ private RecipeOutput(int? min, int? max)
+ {
+ Min = min;
+ Max = max;
+ }
+
+ public static RecipeOutput Any => new(null, null);
+}
+public struct CompiledRecipe
+{
+
+ public Recipe RecipeRef;
+ // public BlueprintId[] InputBlueprints;
+ public ItemEntry[] ItemEntries;
+ public bool IsOrdered;
+}
+public struct ItemEntry
+{
+ public bool RequireAll;
+ public Tags InputTags;
+ public Tags ExcludeTags;
+ public BlueprintId? Blueprint;
+}
+public static class RecipeCompiler
+{
+ public static CompiledRecipe Compile(Recipe recipe) => new()
+ {
+ RecipeRef = recipe,
+ ItemEntries = BuildEntries(recipe),
+ // IsOrdered = recipe.InputsOrdered,
+ };
+ private static ItemEntry[] BuildEntries(Recipe recipe)
+ {
+ var entries = new ItemEntry[recipe.Inputs.Length];
+
+ for (var i = 0; i < entries.Length; i++)
+ {
+ entries[i] = new ItemEntry
+ {
+ RequireAll = recipe.RequireAll[i],
+ InputTags = recipe.Inputs[i],
+ ExcludeTags = recipe.Exclude[i],
+ // Blueprint = recipe.BlueprintIds?[i],
+ };
+ }
+
+ return entries;
+ }
+}
+public record BurnItemRecipe : Recipe
+{
+ public BurnItemRecipe() : base("Burn_item",
+ BlueprintIds: null,
+ RequireAll: [false],
+ Inputs: [new Tags("burnable")],
+ Exclude: [new Tags("burned")],
+ RecipeOutput: RecipeOutput.Any,
+ Action: new RecipeAction("cook"),
+ InputsOrdered: true)
+ {
+
+ }
+
+ public override bool CanProcess(in RecipeContext context)
+ {
+ if (context.Items[0].TryGet(out var temp) && context.Items[0].TryGet(out var burnableTemp) && temp > burnableTemp.Temperature)
+ {
+ return true;
+ }
+ return false;
+ }
+ public override RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder) => new(BurnItem);
+
+ private void BurnItem(RecipeContext context)
+ {
+ // context.Entity[0].Remove();
+ context.Items[0].Add(new BurnedItem(context.Items[0].Get(), "Was Burned as some time thing"));
+ context.Items[0].Set(context.Items[0].Get().WithOut("burnable").With("burned"));
+ context.Items[0].Set($"Burned_{context.Items[0].Get().Value}");
+ if (context.Items[0].Has())
+ {
+ context.Items[0].Set(context.Items[0].Get() * Colors.Black);
+ }
+ else
+ {
+ context.Items[0].Add(Colors.Black);
+ }
+ }
+}
+public record OnionSliceRecipe() : Recipe(Name: "Onion_Slice",
+ BlueprintIds: null,
+ RequireAll: [false],
+ Inputs: [new Tags("onion", "sliceable")],
+ Exclude: [new Tags()],
+ Action: "slice",
+ RecipeOutput: new RecipeOutput(2)
+ )
+{
+ public override bool CanProcess(in RecipeContext context) => true;
+
+ public override RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder)
+ {
+ builder.AddRemove(true);
+ builder.AddCreate(Slice);
+ builder.AddCreate(Slice);
+ return builder.Build();
+ }
+ private Entity Slice(in RecipeContext context)
+ {
+ Span span = stackalloc Entity[1];
+ var signature = context.World.GetSignature(context.Items[0]);
+ context.World.Create(span, signature, 1);
+ PotatoCookRecipe.CopyEntities(context.Items, span, context.World);
+ span[0].Set(new Name("Sliced " + context.Items[0].Get().Value));
+ span[0].Set(new Mass(context.Items[0].Get().Value * .5));
+ span[0].Set(span[0].Get().With("sliced"));
+ return span[0];
+ }
+}
+public record PotatoCookRecipe() : Recipe(Name: "Potato_Cook",
+ BlueprintIds: null,
+ RequireAll: [false],
+ Inputs: [new Tags("potato", "raw")],
+ Exclude: [new Tags()],
+ InputsOrdered: true,
+ Action: "cook",
+ RecipeOutput: new RecipeOutput(1))
+{
+ public override bool CanProcess(in RecipeContext context)
+ {
+ if (!(context.Items[0].TryGet(out var temp) && temp.Fahrenheit > 350))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public override RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder)
+ {
+ builder.AddRemove(true);
+ builder.AddCreate(NewPotato);
+ return builder.Build();
+ }
+ private Entity NewPotato(in RecipeContext context)
+ {
+ Span span = stackalloc Entity[1];
+ var signature = context.World.GetSignature(context.Items[0]);
+ context.World.Create(span, signature, 1);
+ CopyEntity(context.Items[0], span[0], context.World);
+
+ span[0].Set(new Name("Cooked_Potato"));
+ span[0].Set(context.Items[0].Get().With("cooked").WithOut("raw"));
+ // span[0].Set(context.Entity[0].Get());
+ if (context.Items[0].Has())
+ {
+ context.Items[0].Set(context.Items[0].Get() * Colors.Brown);
+ }
+ else
+ {
+ context.Items[0].Add(Colors.Brown);
+ }
+ return span[0];
+ }
+ public static void CopyEntities(Span from, Span to, World world)
+ {
+ Debug.Assert(from.Length == to.Length);
+ for (int i = 0; i < from.Length; i++)
+ {
+ CopyEntity(from[i], to[i], world);
+ }
+
+ }
+ public static void CopyEntity(Entity src, Entity dst, World world)
+{
+ var srcData = world.GetEntityData(src);
+ var dstData = world.GetEntityData(dst);
+
+ var components = srcData.Archetype
+ .GetChunk(srcData.Slot.ChunkIndex)
+ .Components;
+ var componentsDst = dstData.Archetype
+ .GetChunk(dstData.Slot.ChunkIndex)
+ .Components;
+
+ int srcIndex = srcData.Slot.Index;
+ int dstIndex = dstData.Slot.Index;
+
+ for (int i = 0; i < components.Length; i++)
+ {
+ componentsDst[i].SetValue(components[i].GetValue(srcIndex), dstIndex);
+ }
+}
+}
diff --git a/src/Recipes/Recipe.cs.uid b/src/Recipes/Recipe.cs.uid
new file mode 100644
index 0000000..531d7d7
--- /dev/null
+++ b/src/Recipes/Recipe.cs.uid
@@ -0,0 +1 @@
+uid://152ii3ysj30f
diff --git a/src/Recipes/RecipeAction.cs b/src/Recipes/RecipeAction.cs
new file mode 100644
index 0000000..cc5fea7
--- /dev/null
+++ b/src/Recipes/RecipeAction.cs
@@ -0,0 +1,12 @@
+namespace FoodFactory.Recipes;
+
+public readonly record struct RecipeAction
+{
+ public readonly string Value;
+ public RecipeAction(string value)
+ {
+ Value = value.ToLowerInvariant();
+ }
+ public static implicit operator string(RecipeAction name) => name.Value;
+ public static implicit operator RecipeAction(string name) => new(name);
+}
diff --git a/src/Recipes/RecipeAction.cs.uid b/src/Recipes/RecipeAction.cs.uid
new file mode 100644
index 0000000..f98625d
--- /dev/null
+++ b/src/Recipes/RecipeAction.cs.uid
@@ -0,0 +1 @@
+uid://dut1goeo1md46
diff --git a/src/Recipes/RecipeBucket.cs b/src/Recipes/RecipeBucket.cs
new file mode 100644
index 0000000..833703b
--- /dev/null
+++ b/src/Recipes/RecipeBucket.cs
@@ -0,0 +1,37 @@
+namespace FoodFactory.Recipes;
+
+using System;
+using System.Collections.Generic;
+
+public sealed class RecipeBucket
+{
+ public Dictionary Single = [];
+ public Dictionary Ordered = [];
+ public CompiledRecipe[] Unordered = [];
+ public ReadOnlySpan Resolve(Span items)
+ {
+ if (items.Length == 0)
+ {
+ return Unordered;
+ }
+
+ if (items.Length == 1)
+ {
+ if (Single.TryGetValue(items[0], out var r))
+ {
+ return r;
+ }
+
+ return Unordered;
+ }
+
+ var main = items[0];
+
+ if (Ordered.TryGetValue(main, out var ordered))
+ {
+ return ordered;
+ }
+
+ return Unordered;
+ }
+}
diff --git a/src/Recipes/RecipeBucket.cs.uid b/src/Recipes/RecipeBucket.cs.uid
new file mode 100644
index 0000000..7b5a68e
--- /dev/null
+++ b/src/Recipes/RecipeBucket.cs.uid
@@ -0,0 +1 @@
+uid://cfhklflid8ed1
diff --git a/src/Recipes/RecipeContext.cs b/src/Recipes/RecipeContext.cs
new file mode 100644
index 0000000..e330c35
--- /dev/null
+++ b/src/Recipes/RecipeContext.cs
@@ -0,0 +1,20 @@
+namespace FoodFactory.Recipes;
+
+using System;
+using Arch.Core;
+
+public readonly ref struct RecipeContext
+{
+ public readonly World World;
+
+ public RecipeContext(World world, Span entity) : this()
+ {
+ World = world;
+ Items = entity;
+ }
+
+ public readonly Span Items;
+ // optional later:
+ // public readonly Machine Machine;
+ // public readonly float Delta;
+}
diff --git a/src/Recipes/RecipeContext.cs.uid b/src/Recipes/RecipeContext.cs.uid
new file mode 100644
index 0000000..fcc7e3d
--- /dev/null
+++ b/src/Recipes/RecipeContext.cs.uid
@@ -0,0 +1 @@
+uid://cjamv4y4aikhc
diff --git a/src/Recipes/RecipeName.cs b/src/Recipes/RecipeName.cs
new file mode 100644
index 0000000..c802f17
--- /dev/null
+++ b/src/Recipes/RecipeName.cs
@@ -0,0 +1,20 @@
+namespace FoodFactory.Recipes;
+
+// public record SingleItemRecipe(string Name, Tags Required, Tags Exclude) : Recipe(Name)
+// {
+
+// }
+// public record MultipleItemRecipe(string Name, params ItemInput[] Inputs) : Recipe(Name)
+// {
+
+// }
+public readonly record struct RecipeName
+{
+ public readonly string Name;
+ public RecipeName(string name)
+ {
+ Name = name.ToLowerInvariant();
+ }
+ public static implicit operator string(RecipeName name) => name.Name;
+ public static implicit operator RecipeName(string name) => new(name);
+}
diff --git a/src/Recipes/RecipeName.cs.uid b/src/Recipes/RecipeName.cs.uid
new file mode 100644
index 0000000..ef2fe27
--- /dev/null
+++ b/src/Recipes/RecipeName.cs.uid
@@ -0,0 +1 @@
+uid://b635p37fwu0xl
diff --git a/src/Recipes/RecipeResult.cs b/src/Recipes/RecipeResult.cs
new file mode 100644
index 0000000..9309a04
--- /dev/null
+++ b/src/Recipes/RecipeResult.cs
@@ -0,0 +1,26 @@
+namespace FoodFactory.Recipes;
+
+using System;
+
+public readonly ref struct RecipeResult
+{
+ public readonly int RemoveLength => Remove.Length;
+ public readonly int CreateLength => Create.Length;
+ public readonly ReadOnlySpan Remove; // destroy original
+
+ public RecipeResult(ReadOnlySpan remove, ReadOnlySpan create) : this()
+ {
+ Remove = remove;
+ Create = create;
+ Mutate = null;
+ }
+
+ public readonly ReadOnlySpan Create; // multi-output
+
+ public readonly Action? Mutate; // component changes
+
+ public RecipeResult(Action mutate) : this()
+ {
+ Mutate = mutate;
+ }
+}
diff --git a/src/Recipes/RecipeResult.cs.uid b/src/Recipes/RecipeResult.cs.uid
new file mode 100644
index 0000000..1aaa6d0
--- /dev/null
+++ b/src/Recipes/RecipeResult.cs.uid
@@ -0,0 +1 @@
+uid://ctyimxkx8bomh
diff --git a/src/Recipes/RecipeResultBuilder.cs b/src/Recipes/RecipeResultBuilder.cs
new file mode 100644
index 0000000..801e146
--- /dev/null
+++ b/src/Recipes/RecipeResultBuilder.cs
@@ -0,0 +1,34 @@
+namespace FoodFactory.Recipes;
+
+using System;
+using Arch.Core;
+
+public ref struct RecipeResultBuilder
+{
+ private Span _remove;
+ private Span _create;
+ private int _removeCount;
+ private int _createCount;
+
+ public RecipeResultBuilder(Span remove, Span create)
+ {
+ _remove = remove;
+ _create = create;
+ _removeCount = 0;
+ _createCount = 0;
+ }
+
+ public void AddRemove(bool value) => _remove[_removeCount++] = value;
+ public void AddCreate(ItemBuilder item) => _create[_createCount++] = item;
+ public void Clear()
+ {
+ _removeCount = 0;
+ _createCount = 0;
+ }
+ public readonly RecipeResult Build()
+ => new(
+ _remove[.._removeCount],
+ _create[.._createCount]);
+}
+public delegate Entity ItemBuilder(in RecipeContext ctx);
+
diff --git a/src/Recipes/RecipeResultBuilder.cs.uid b/src/Recipes/RecipeResultBuilder.cs.uid
new file mode 100644
index 0000000..c55a4fa
--- /dev/null
+++ b/src/Recipes/RecipeResultBuilder.cs.uid
@@ -0,0 +1 @@
+uid://ba6ll7cygo6hg
diff --git a/src/Recipes/Recipes.cs b/src/Recipes/Recipes.cs
index 37f7239..6569051 100644
--- a/src/Recipes/Recipes.cs
+++ b/src/Recipes/Recipes.cs
@@ -1,82 +1,81 @@
namespace FoodFactory.Recipes;
using System;
-using System.Collections;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
-using Arch.Core;
-using Arch.Core.Extensions;
-using FastExpressionCompiler.ImTools;
+using ChickenGameTest;
using FoodFactory.Items;
using Godot;
-using Parlot.Fluent;
using SJK.Functional;
-public class Recipes
+
+public record struct RecipeEntryKey(RecipeAction Action, int Inputs, BlueprintId? FirstBlueprintId, RecipeOutput OutputsCount);
+
+public interface IRecipes
{
- private readonly Dictionary> _actions = [];
+ Option GetRecipeByName(RecipeName name);
+ RecipeEnumerator GetRecipes(RecipeAction action, int inputs, Tags[] itemTags, BlueprintId[] blueprintIds, RecipeOutput outputCount, Span mapping);
+}
+public readonly record struct RecipeInput(RecipeAction Action, int Inputs, Tags[] ItemTags, BlueprintId[] BlueprintIds, RecipeOutput OutputCount);
+public class Recipes : IRecipes
+{
+ private readonly Dictionary _sortedRecipes = [];
private readonly Dictionary _recipes = [];
public Option GetRecipeByName(RecipeName name) => _recipes.GetValue(name).ToStructOption();
- public Blueprint TESTBlueprint;
public Recipes()
{
- //TODO Utilize the singtaure ssytem to create the item, the have a post proccess step that would be for setting propertied
- var rawPotatoBlueprint = TESTBlueprint = new Blueprint("Potato", static ctx => ctx.World.Create(new Name("Potato_raw"), new Tags("potato", "raw", "vegetable"), new Temperature(71, TemperatureUnit.Fahrenheit), ctx.BluePrintId));
- var recipe = new PotatoCookRecipe();
- _recipes.Add(new RecipeName(recipe.Name), recipe);
- var compiledRecipe = new CompiledRecipe() { IsOrdered = true, RecipeRef = recipe, InputBlueprints = [new BlueprintId(rawPotatoBlueprint)], ItemEntries = [new CompiledRecipe.ItemEntry() { InputTags = recipe.Inputs[0], ExcludeTags = recipe.Exclude[0], RequireAll = recipe.RequireAll[0] }] };
- _actions.Add(new("cook"), new Dictionary() { [1] = new RecipeBucket() {Single = new Dictionary(){[new BlueprintId(rawPotatoBlueprint)] = [compiledRecipe] }, Unordered = [compiledRecipe] } });
+ var builder = new RecipesBuilder();
+ builder.Add(new PotatoCookRecipe());
+ builder.Add(new BurnItemRecipe());
+ builder.Add(new OnionSliceRecipe());
+ _sortedRecipes = builder.Build();
+ _recipes = builder.CompiledRecipes.Select(f => f.RecipeRef).ToDictionary(k => new RecipeName(k.Name));
}
- public List<(Recipe Recipe, int[]? Mapping)> GetRecipes(RecipeAction action, int inputs, Tags[] itemTags, BlueprintId[] blueprintIds)
+ public unsafe RecipeEnumerator GetRecipes(RecipeAction action, int inputs, Tags[] itemTags, BlueprintId[] blueprintIds, RecipeOutput outputCount, Span mapping)
{
- var list = new List<(Recipe, int[])>();
Debug.Assert(inputs > 0);
Debug.Assert(inputs == itemTags.Length);
- if (!_actions.TryGetValue(action, out var inputAmount))
+ var key = new RecipeEntryKey(action, inputs, blueprintIds.Length > 0 ? blueprintIds[0] : null, outputCount);
+ if (!_sortedRecipes.TryGetValue(key, out var bucket))
{
- return null;
+ return new RecipeEnumerator();
}
- if (!inputAmount.TryGetValue(inputs, out var blueprints))
- {
- return null;
- }
- var recipes = blueprints.Resolve(blueprintIds);
-
-
- var mapping = new int[itemTags.Length];
- var used = new bool[itemTags.Length];
- for (int i = 0; i < recipes.Length; i++)
- {
- var item = recipes[i];
- if (inputs == 1 && IsValid(itemTags[0], item.ItemEntries[0]))
- {
- list.Add((item.RecipeRef, null));
- }
- else if (item.IsOrdered)
- {
- for (int ii = 0; ii < itemTags.Length; ii++)
- {
- if (!IsValid(itemTags[ii], item.ItemEntries[ii]))
- {
- continue;
- }
- }
- list.Add((item.RecipeRef, null));
- }
- else if (CanPossiblyMatch(itemTags, item))
- {
- if (Match(itemTags, item.ItemEntries, 0, used, mapping))
- {
- list.Add((item.RecipeRef, mapping));
- }
- }
- }
- return list;
+ var recipes = bucket.Resolve(blueprintIds);
+ return new RecipeEnumerator(recipes, new(action,inputs,itemTags,blueprintIds,outputCount), &Filter, mapping);
}
- private static bool IsValid(Tags tags, CompiledRecipe.ItemEntry compiled)
+ private static bool Filter(RecipeInput input, CompiledRecipe compiledRecipe, Span mapping, out RecipeMatch recipeMatch)
+ {
+ if (input.Inputs == 1 && IsValid(input.ItemTags[0], compiledRecipe.ItemEntries[0]))
+ {
+ recipeMatch = new RecipeMatch(compiledRecipe.RecipeRef, []);
+ return true;
+ }
+ else if (compiledRecipe.IsOrdered)
+ {
+ for (var ii = 0; ii < input.ItemTags.Length; ii++)
+ {
+ if (!IsValid(input.ItemTags[ii], compiledRecipe.ItemEntries[ii]))
+ {
+ continue;
+ }
+ }
+ recipeMatch = new RecipeMatch(compiledRecipe.RecipeRef, []);
+ return true;
+ }
+ else if (CanPossiblyMatch(input.ItemTags, compiledRecipe))
+ {
+ Span used = stackalloc bool[input.ItemTags.Length];
+ if (Match(input.ItemTags, compiledRecipe.ItemEntries, 0, used, mapping))
+ {
+ recipeMatch = new RecipeMatch(compiledRecipe.RecipeRef, mapping);
+ return true;
+ }
+ }
+ recipeMatch = default;
+ return false;
+ }
+ private static bool IsValid(Tags tags, ItemEntry compiled)
{
if (!(compiled.RequireAll ? tags.ContainsAll(compiled.InputTags) : tags.ContainsAny(compiled.InputTags)))
{
@@ -92,7 +91,7 @@ public class Recipes
{
foreach (var entry in recipe.ItemEntries)
{
- bool found = false;
+ var found = false;
foreach (var item in items)
{
@@ -104,17 +103,19 @@ public class Recipes
}
if (!found)
+ {
return false;
+ }
}
return true;
}
private static bool Match(
- Tags[] items,
- CompiledRecipe.ItemEntry[] entries,
- int depth,
- Span used,
- Span mapping)
+ Tags[] items,
+ ItemEntry[] entries,
+ int depth,
+ Span used,
+ Span mapping)
{
if (depth == entries.Length)
{
@@ -190,7 +191,7 @@ public class Recipes
{
return [.. mapping];
}
- for (int i = 0; i < test.Length; i++)
+ for (var i = 0; i < test.Length; i++)
{
if (used[i])
{
@@ -215,199 +216,114 @@ public class Recipes
return backTrace(0);
}
}
-public abstract record Recipe(string Name, BlueprintId[]? BlueprintIds, bool[] RequireAll, Tags[] Inputs, Tags[] Exclude)
+public class RecipesBuilder
{
- public abstract bool CanProcess(in RecipeContext context);
- public abstract RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder);
-}
-public record PotatoCookRecipe() : Recipe(Name: "Potato_Cook", BlueprintIds: null, RequireAll: [false], Inputs: [new Tags("potato")], Exclude: [new Tags()])
-{
- public override bool CanProcess(in RecipeContext context)
+
+ private readonly Dictionary _data = [];
+ private readonly List _compiledRecipes = [];
+ public IReadOnlyCollection CompiledRecipes => _compiledRecipes;
+ public void Add(Recipe recipe)
{
- if (!context.Entity[0].Has())
+ var compiled = RecipeCompiler.Compile(recipe);
+ _compiledRecipes.Add(compiled);
+ var key = new RecipeEntryKey(recipe.Action, recipe.Inputs.Length, recipe.BlueprintIds?[0], recipe.RecipeOutput);
+ var key2 = new RecipeEntryKey(recipe.Action, recipe.Inputs.Length, recipe.BlueprintIds?[0], RecipeOutput.Any);
+ //TODO have items automatic added to any if not a zero output recipe
+ if (!_data.TryGetValue(key, out var bucket))
{
- return false;
+ bucket = new BucketBuilder();
+ _data[key] = bucket;
}
- return true;
- }
-
- public override RecipeResult Process(in RecipeContext context, ref RecipeResultBuilder builder)
- {
- builder.AddRemove(true);
- builder.AddCreate(NewPotato);
- return builder.Build();
- }
-
- private Entity NewPotato(in RecipeContext context)
- {
- Span span = stackalloc Entity[1];
- var signature = context.World.GetSignature(context.Entity[0]);
- context.World.Create(span, signature, 1);
-
- span[0].Set(new Name("Cooked_Potato"));
- span[0].Set(context.Entity[0].Get().With("cooked").WithOut("raw"));
- span[0].Set(context.Entity[0].Get());
- return span[0];
- }
-}
-public ref struct RecipeResultBuilder
-{
- private Span _remove;
- private Span _create;
- private int _removeCount;
- private int _createCount;
-
- public RecipeResultBuilder(Span remove, Span create)
- {
- _remove = remove;
- _create = create;
- _removeCount = 0;
- _createCount = 0;
- }
-
- public void AddRemove(bool value) => _remove[_removeCount++] = value;
- public void AddCreate(ItemBuilder item) => _create[_createCount++] = item;
-
- public RecipeResult Build()
- => new RecipeResult(
- _remove.Slice(0, _removeCount),
- _create.Slice(0, _createCount));
-}
-public delegate Entity ItemBuilder(in RecipeContext ctx);
-public readonly ref struct RecipeContext
-{
- public readonly World World;
-
- public RecipeContext(World world, Span entity) : this()
- {
- World = world;
- Entity = entity;
- }
-
- public readonly Span Entity;
- // optional later:
- // public readonly Machine Machine;
- // public readonly float Delta;
-}
-public readonly ref struct RecipeResult
-{
- public readonly int RemoveLength => Remove.Length;
- public readonly int CreateLength => Create.Length;
- public readonly ReadOnlySpan Remove; // destroy original
-
- public RecipeResult(ReadOnlySpan remove, ReadOnlySpan create) : this()
- {
- Remove = remove;
- Create = create;
- Mutate = null;
- }
-
- public readonly ReadOnlySpan Create; // multi-output
-
- public readonly Action? Mutate; // component changes
-
- public RecipeResult(Action mutate) : this()
- {
- Mutate = mutate;
- }
-}
-public struct CompiledRecipe
-{
-
- public Recipe RecipeRef;
- public BlueprintId[] InputBlueprints;
- public ItemEntry[] ItemEntries;
- public bool IsOrdered;
- public struct ItemEntry
- {
- public bool RequireAll;
- public Tags InputTags;
- public Tags ExcludeTags;
- }
-}
-// public record SingleItemRecipe(string Name, Tags Required, Tags Exclude) : Recipe(Name)
-// {
-
-// }
-// public record MultipleItemRecipe(string Name, params ItemInput[] Inputs) : Recipe(Name)
-// {
-
-// }
-public readonly record struct RecipeName
-{
- public readonly string Name;
- public RecipeName(string name)
- {
- Name = name.ToLowerInvariant();
- }
- public static implicit operator string(RecipeName name) => name.Name;
-}
-public readonly record struct RecipeAction
-{
- public readonly string Value;
- public RecipeAction(string value)
- {
- Value = value.ToLowerInvariant();
- }
- public static implicit operator string(RecipeAction name) => name.Value;
-}
-public readonly record struct BlueprintId
-{
- public readonly int Id;
- public Blueprint Blueprint => _registry.GetEntry(Id);
- private static Registry _registry = new();
- public BlueprintId(Blueprint blueprint)
- {
- Id = _registry.GetOrCreate(blueprint);
-
- }
-}
-public record Blueprint(string Name, Func Factory)
-{
-
-}
-public struct BlueprintContext
-{
- public World World;
- public BlueprintId BluePrintId;
-}
-public sealed class RecipeBucket
-{
- // 1 input → direct blueprint lookup
- public Dictionary Single = [];
-
- // ordered multi-input → first item is anchor
- public Dictionary Ordered = [];
-
- // fallback (unordered / no blueprint)
- public CompiledRecipe[] Unordered = [];
- ///
- /// Resloves Blueprints, if span is length 0, tehn Unordred is returned imdetly
- ///
- ///
- ///
- public ReadOnlySpan Resolve(Span items)
-{
- if (items.Length == 0)
+ bucket.Add(compiled, recipe.BlueprintIds ?? []);
+ if (recipe.RecipeOutput == RecipeOutput.Any)
{
- return Unordered;
+ return;
+ }
+ if (!_data.TryGetValue(key2, out bucket))
+ {
+ bucket = new BucketBuilder();
+ _data[key2] = bucket;
+ }
+ bucket.Add(compiled, recipe.BlueprintIds ?? []);
+ }
+ public Dictionary Build()
+ {
+ var result = new Dictionary();
+
+ foreach (var (key, bucket) in _data)
+ {
+ result[key] = bucket.Build();
}
- if (items.Length == 1)
- {
- if (Single.TryGetValue(items[0], out var r))
- return r;
+ return result;
+ }
+ private sealed class BucketBuilder
+ {
+ private readonly Dictionary> _single = [];
+ private readonly Dictionary> _ordered = [];
+ private readonly List _unordered = [];
- return Unordered;
+ public void Add(CompiledRecipe recipe, ReadOnlySpan inputs)
+ {
+ if (inputs.Length == 0)
+ {
+ _unordered.Add(recipe);
+ return;
+ }
+
+ if (inputs.Length == 1)
+ {
+ var list = GetOrCreate(_single, inputs[0]);
+ list.Add(recipe);
+ return;
+ }
+
+ // multi-input → ordered (anchor = first)
+ if (recipe.IsOrdered)
+ {
+ var orderedList = GetOrCreate(_ordered, inputs[0]);
+ orderedList.Add(recipe);
+ }
+ else
+ {
+ _unordered.Add(recipe);
+ }
}
- var main = items[0];
-
- if (Ordered.TryGetValue(main, out var ordered))
+ public RecipeBucket Build()
{
- return ordered;
+ return new RecipeBucket
+ {
+ Single = ToArrayDict(_single),
+ Ordered = ToArrayDict(_ordered),
+ Unordered = [.. _unordered]
+ };
}
- return Unordered;
-}
+ private static List GetOrCreate(
+ Dictionary> dict,
+ BlueprintId key)
+ {
+ if (!dict.TryGetValue(key, out var list))
+ {
+ list = new List(4);
+ dict[key] = list;
+ }
+
+ return list;
+ }
+
+ private static Dictionary ToArrayDict(
+ Dictionary> source)
+ {
+ var result = new Dictionary(source.Count);
+
+ foreach (var (key, list) in source)
+ {
+ result[key] = [.. list];
+ }
+
+ return result;
+ }
+ }
}
diff --git a/src/Recipes/Recipes.cs.uid b/src/Recipes/Recipes.cs.uid
new file mode 100644
index 0000000..29bde9f
--- /dev/null
+++ b/src/Recipes/Recipes.cs.uid
@@ -0,0 +1 @@
+uid://cp61k5vfvknv8
diff --git a/src/VoxelGrid/Balancer.cs b/src/VoxelGrid/Balancer.cs
new file mode 100644
index 0000000..3e7d4d1
--- /dev/null
+++ b/src/VoxelGrid/Balancer.cs
@@ -0,0 +1,61 @@
+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, IProvide
+{
+ public override void _Notification(int what) => this.Notify(what);
+ private BeltPortHost _insertLogic = default!;
+ public IBeltPortHost Value() => _insertLogic;
+ IVoxelGridRegistry IProvide.Value() => GridRegistry;
+ [Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn();
+ private List _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 OutputPorts => _insertLogic.GetPorts().OfType().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;
+ }
+}
diff --git a/src/VoxelGrid/Balancer.cs.uid b/src/VoxelGrid/Balancer.cs.uid
new file mode 100644
index 0000000..a33e56b
--- /dev/null
+++ b/src/VoxelGrid/Balancer.cs.uid
@@ -0,0 +1 @@
+uid://opbkqoaa7x2n
diff --git a/src/VoxelGrid/BeltPort.cs b/src/VoxelGrid/BeltPort.cs
index 9f00204..162143e 100644
--- a/src/VoxelGrid/BeltPort.cs
+++ b/src/VoxelGrid/BeltPort.cs
@@ -1,14 +1,9 @@
namespace ChickenGameTest;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
-using SJK.Functional;
[Tool]
[Meta(typeof(IAutoNode))]
@@ -21,11 +16,9 @@ public partial class BeltPort : Node3D, IBeltPort
[Export] public Direction Face { get; set; } = default!;
[Export] public int Width { get; set; } = default!;
[Export] public PortAccess Access { get; set; } = default!;
- [Export] public Path3D Path { get; set; } = default!;
[Export] public string PortName { get; set; } = "";
[Dependency] public IItemRenderer ItemRenderer => this.DependOn();
public BeltPortProfile Profile => new(GridTransform3D.FromGodot(GlobalTransform), Width, Access);
- [Dependency] public IItemTransferAnimator ItemTransferAnimator => this.DependOn(() => new CurveItemTransfer() { Curve3D = Path.Curve, Tree = GetTree(), ItemRenderer = ItemRenderer, Transform3D = GlobalTransform });
private VoxelGuid _guid = new(Guid.Empty);
public void OnResolved()
{
@@ -37,26 +30,7 @@ public partial class BeltPort : Node3D, IBeltPort
_guid = Grid.Register(this, [.. (this as IBeltPort).Points()]);
GD.Print(_guid);
}
- public override void _Process(double delta)
- {
- 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);
- // GD.Print(_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();
- _itemsDummys.RemoveAt(i);
- i--;
- }
- }
- }
+ public override void _Process(double delta) => DebugDraw3D.DrawLine(GlobalPosition, GlobalTransform * Face.ToVector(), Colors.Red);
public override void _ExitTree()
{
@@ -69,20 +43,7 @@ public partial class BeltPort : Node3D, IBeltPort
}
public bool CanAccept(IBeltItem item, LaneSpan laneSpan, float beltT) => Access.HasFlag(PortAccess.In) && InsertLogic.CanAccept(this, item);
- List<(float i, IBeltItem beltItem)> _itemsDummys = [];
-
public bool TryInsert(IBeltItem item, LaneSpan laneSpan, float beltT) => CanAccept(item, laneSpan, beltT) && InsertLogic.CanInsert(this, item);
- // {
- // 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);
- // // GD.Print(item.ToString());
- // // _itemsDummys.Add((0,item));
- // // item.Dispose();
- // return true;
- // throw new System.NotImplementedException();
- // }
}
public interface IBeltItemInsertLogic
@@ -90,106 +51,3 @@ public interface IBeltItemInsertLogic
bool CanInsert(IBeltPort beltPort, IBeltItem item);
bool CanAccept(IBeltPort beltPort, IBeltItem item);
}
-public interface IBeltPortHost
-{
- IBeltItemInsertLogic ResolveInsertLogic(IBeltPort port);
-}
-public class BeltPortHost : IBeltPortHost
-{
- private readonly List<(Func match, Func factory)> _bindings
- = new();
-
- public BeltPortHost Bind(
- Func match,
- Func factory)
- {
- _bindings.Add((match, factory));
- return this;
- }
- private HashSet _ports = [];
- public IBeltItemInsertLogic? Default;
-
- ///
- /// Resolve the insert logic for a port. If no matching bind exists then the default is returned if supplied. Other wise throws an 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 GetPorts() => _ports;
-}
-public interface IItemTransferAnimator
-{
- Tween StartTransfer(
- ConveyorSlice item,
- Action onFinished = null);
-}
-
-public class InstanceItemTransfer : IItemTransferAnimator
-{
- public SceneTree Tree = default!;
- public Func AcceptFunc = default!;
- public Tween StartTransfer(ConveyorSlice item, Action onFinished = null)
- {
- AcceptFunc(item);
- onFinished?.Invoke();
- return Tree.CreateTween();
- throw new NotImplementedException();
- }
-}
-public class CurveItemTransfer : IItemTransferAnimator
-{
- public Curve3D Curve3D = default!;
- public IItemRenderer ItemRenderer = default!;
- public Func AcceptFunc = default!;
- public SceneTree Tree = default!;
- public Transform3D Transform3D;
- public Tween AnimateAlongCurve(
- ConveyorSlice item,
- Curve3D curve,
- float duration,
- IItemRenderer renderer)
- {
- float length = curve.GetBakedLength();
-
- var tween = Tree.CreateTween();
-
- tween.TweenMethod(
- Callable.From(t =>
- {
- //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);
- // GD.PrintS(Transform3D * curve.SampleBakedWithRotation(t).Origin,1/duration,(renderer as TestItemRendered)._items[item].GlobalPosition);
- }),
- 0f,
- length,
- duration
- );
- return tween;
- }
- 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;
- }
-}
diff --git a/src/VoxelGrid/BeltPortHost.cs b/src/VoxelGrid/BeltPortHost.cs
new file mode 100644
index 0000000..182b97f
--- /dev/null
+++ b/src/VoxelGrid/BeltPortHost.cs
@@ -0,0 +1,48 @@
+namespace ChickenGameTest;
+
+using System;
+using System.Collections.Generic;
+
+public interface IBeltPortHost
+{
+ IBeltItemInsertLogic ResolveInsertLogic(IBeltPort port);
+}
+public class BeltPortHost : IBeltPortHost
+{
+ private readonly List<(Func match, Func factory)> _bindings
+ = new();
+
+ public BeltPortHost Bind(
+ Func match,
+ Func factory)
+ {
+ _bindings.Add((match, factory));
+ return this;
+ }
+ private HashSet _ports = [];
+ public IBeltItemInsertLogic? Default;
+
+ ///
+ /// Resolve the insert logic for a port. If no matching bind exists then the default is returned if supplied. Other wise throws an 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 GetPorts() => _ports;
+}
diff --git a/src/VoxelGrid/BeltPortHost.cs.uid b/src/VoxelGrid/BeltPortHost.cs.uid
new file mode 100644
index 0000000..2b0860f
--- /dev/null
+++ b/src/VoxelGrid/BeltPortHost.cs.uid
@@ -0,0 +1 @@
+uid://mimkyombngwg
diff --git a/src/VoxelGrid/ConveyorItemRender.cs b/src/VoxelGrid/ConveyorItemRender.cs
index 1618351..fc32f23 100644
--- a/src/VoxelGrid/ConveyorItemRender.cs
+++ b/src/VoxelGrid/ConveyorItemRender.cs
@@ -1,10 +1,7 @@
namespace ChickenGameTest;
-using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
@@ -55,6 +52,32 @@ public interface IItemRenderer
void UpdateTransform(IBeltItem beltItem, Transform3D newTransform, float time);
void Remove(IBeltItem beltItem);
}
+public partial class ItemRenderSimple : Node3D, IItemRenderer
+{
+ public Dictionary _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 _items = [];
diff --git a/src/VoxelGrid/ItemConveyor.cs b/src/VoxelGrid/ItemConveyor.cs
index 90ca108..0274269 100644
--- a/src/VoxelGrid/ItemConveyor.cs
+++ b/src/VoxelGrid/ItemConveyor.cs
@@ -1,14 +1,11 @@
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 System.Diagnostics.CodeAnalysis;
public interface IMovementConveyor
{
diff --git a/src/VoxelGrid/ItemSpawner.cs b/src/VoxelGrid/ItemSpawner.cs
new file mode 100644
index 0000000..1a2d048
--- /dev/null
+++ b/src/VoxelGrid/ItemSpawner.cs
@@ -0,0 +1,70 @@
+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
+{
+ public override void _Notification(int what) => this.Notify(what);
+
+ [Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn();
+ [Dependency] public IBlueprintManger ItemFactory => this.DependOn();
+ [Dependency] public World World => this.DependOn();
+ [Dependency] public IRecipes Recipes => this.DependOn();
+ 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.");
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/VoxelGrid/ItemSpawner.cs.uid b/src/VoxelGrid/ItemSpawner.cs.uid
new file mode 100644
index 0000000..75ec960
--- /dev/null
+++ b/src/VoxelGrid/ItemSpawner.cs.uid
@@ -0,0 +1 @@
+uid://btmbv7oaeps4p
diff --git a/src/VoxelGrid/ItemSpawner.tscn b/src/VoxelGrid/ItemSpawner.tscn
new file mode 100644
index 0000000..c41817c
--- /dev/null
+++ b/src/VoxelGrid/ItemSpawner.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://bktqs1lw6go4"]
+
+[ext_resource type="Script" uid="uid://btmbv7oaeps4p" path="res://src/VoxelGrid/ItemSpawner.cs" id="1_3dxrm"]
+[ext_resource type="PackedScene" uid="uid://bfwvlnurlcbwk" path="res://assets/kenney_conveyor-kit/Models/GLB format/cover-hopper.glb" id="2_552yl"]
+[ext_resource type="Script" uid="uid://ee5aoxi8mjnw" path="res://src/VoxelGrid/BeltPort.cs" id="3_0b0h5"]
+
+[node name="ItemSpawner" type="Node3D" unique_id=966349707]
+script = ExtResource("1_3dxrm")
+
+[node name="cover-hopper2" parent="." unique_id=2099493372 instance=ExtResource("2_552yl")]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 0)
+
+[node name="Node3D" type="Node3D" parent="." unique_id=430904887]
+script = ExtResource("3_0b0h5")
+Face = 4
+Width = 1
+Access = 2
diff --git a/src/VoxelGrid/OvenTest.cs b/src/VoxelGrid/OvenTest.cs
index 7d1b61c..5915de8 100644
--- a/src/VoxelGrid/OvenTest.cs
+++ b/src/VoxelGrid/OvenTest.cs
@@ -2,38 +2,50 @@ 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, IProvide
{
- private BeltPortHost _insertLogic;
- public IBeltPortHost Value() => _insertLogic;
public override void _Notification(int what) => this.Notify(what);
+ private BeltPortHost _insertLogic = default!;
+ public IBeltPortHost Value() => _insertLogic;
[Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn();
+ [Dependency] public IRecipes Recipes => this.DependOn();
IVoxelGridRegistry IProvide.Value() => GridRegistry;
public GridTransform3D VoxelTransform
{
get => GridTransform3D.FromGodot(GlobalTransform);
set => GlobalTransform = value.ToGodot();
}
- private Dictionary? _placeholderItem = null;
- private VoxelGuid _guid = default;
+ 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) => _placeholderItem is null;
+ bool canAccept(IBeltPort port, IBeltItem item) => _itemBeingHeld.Id == -1 && !_itemBeingHeld.IsAlive();
bool canInsert(IBeltPort beltPort, IBeltItem item)
{
- _placeholderItem = (item as TestItem).PlaceHolderData;
- item.Dispose();
- GD.Print("Added Item");
- return true;
+ if (item is IBeltItemData itemData)
+ {
+ _itemBeingHeld = itemData.GetItem();
+ item.Dispose();
+ GD.Print("Added Item");
+ return true;
+ }
+ throw new NotImplementedException();
}
_guid = GridRegistry.Register(this, VoxelTransform.Origin);
this.Provide();
@@ -43,22 +55,54 @@ public partial class OvenTest : Node3D, IProvide, IProvide
{
- if (_placeholderItem is null)
+ if (_itemBeingHeld.Id == -1 && !_itemBeingHeld.IsAlive())//TODO have a better way of dertming if item is valid, possibly nullable
{
return;
}
- _placeholderItem.GetValue("temp").IfSome(some => _placeholderItem["temp"] = (float)some + 1);
- if (_placeholderItem.GetValue("temp").Map(f => ((float)f) < 5).Or(true))
+
+ if (!_itemBeingHeld.TryGet(out var temp))
{
return;
}
- var port = _insertLogic.GetPorts().FirstOrNone(port => port is BeltPort beltPort && beltPort.PortName == "OutPut").Bind(f => f.GetPortFacing(GridRegistry));
- if (port.HasValue(out var v) && _placeholderItem is not null && v.TryInsert(new TestItem() { PlaceHolderData = _placeholderItem }, LaneSpan.One, 0))
+ temp.Kelvin += new TemperatureDelta(5f, TemperatureUnit.Fahrenheit).KelvinDelta;
+ _itemBeingHeld.Set(temp);
+
+ Span items = [_itemBeingHeld];
+ var context = new RecipeContext(World.Worlds[0], items);
+ var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
+ Span mapping = stackalloc int[1];
+ var recipes = Recipes.GetRecipes(new RecipeAction("cook"), 1, [_itemBeingHeld.Get()], [], RecipeOutput.Any, mapping);
+ // Span created = stackalloc Entity[10];
+ unsafe
{
- _placeholderItem = null;
+ 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(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);
@@ -79,3 +123,123 @@ public class DelegateInsertBeltItemLogic : IBeltItemInsertLogic
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 Mapping;
+
+ public RecipeMatch(
+ Recipe recipe,
+ ReadOnlySpan 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 _recipes;
+ private readonly RecipeInput _input;
+ private readonly Span _mapping;
+ private readonly delegate*, out RecipeMatch, bool> _filter;
+ public RecipeEnumerator(ReadOnlySpan compiledRecipes, RecipeInput input, delegate*, out RecipeMatch, bool> filter, Span 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(
+ ref TRecipeEnumerator recipes,
+ scoped ref RecipeContext context,
+ scoped ref RecipeResultBuilder builder,
+ delegate* destroyEntity,
+ out Span 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* destroyEntity,
+ out Span 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]);
+ }
+ }
+ }
+ }
+}
diff --git a/src/VoxelGrid/SlicerTest.cs b/src/VoxelGrid/SlicerTest.cs
new file mode 100644
index 0000000..1943be0
--- /dev/null
+++ b/src/VoxelGrid/SlicerTest.cs
@@ -0,0 +1,106 @@
+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, IProvide
+{
+ public override void _Notification(int what) => this.Notify(what);
+ private BeltPortHost _insertLogic = default!;
+ public IBeltPortHost Value() => _insertLogic;
+ [Dependency] public IVoxelGridRegistry GridRegistry => this.DependOn();
+ [Dependency] public IRecipes Recipes => this.DependOn();
+ IVoxelGridRegistry IProvide.Value() => GridRegistry;
+ public GridTransform3D VoxelTransform
+ {
+ get => GridTransform3D.FromGodot(GlobalTransform);
+ set => GlobalTransform = value.ToGodot();
+ }
+ private Entity _itemBeingHeld = Entity.Null;
+ private List 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 beltItemData && beltItemData.GetItem().TryGet(out var tags) && tags.Contains(TagRegistry.GetTag("sliceable"));
+ bool canInsert(IBeltPort beltPort, IBeltItem item)
+ {
+ if (item is IBeltItemData 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());
+ sliced.RemoveAt(0);
+ }
+ }
+ if (_itemBeingHeld.Id == -1)//TODO have a better way of dertming if item is valid, possibly nullable
+ {
+ return;
+ }
+
+ Span items = [_itemBeingHeld];
+ var context = new RecipeContext(World.Worlds[0], items);
+ var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
+ Span mapping = stackalloc int[1];
+ // var recipe = new PotatoCookRecipe();
+ var recipes = Recipes.GetRecipes("slice", 1, [_itemBeingHeld.Get()], [], 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();
+ }
+}
diff --git a/src/VoxelGrid/SlicerTest.cs.uid b/src/VoxelGrid/SlicerTest.cs.uid
new file mode 100644
index 0000000..44588cc
--- /dev/null
+++ b/src/VoxelGrid/SlicerTest.cs.uid
@@ -0,0 +1 @@
+uid://yec84plemjv1
diff --git a/src/VoxelGrid/TestItemConveyor.cs b/src/VoxelGrid/TestItemConveyor.cs
index cd4767d..477412b 100644
--- a/src/VoxelGrid/TestItemConveyor.cs
+++ b/src/VoxelGrid/TestItemConveyor.cs
@@ -8,6 +8,8 @@ using System.Collections.Generic;
using System.Linq;
using Chickensoft.Sync.Primitives;
using SJK.Functional;
+using FoodFactory.Recipes;
+using Arch.Core;
public class Sorted1DList
{
@@ -258,7 +260,6 @@ public partial class TestItemConveyor : Node, IMovementConveyor
var guid = GridRegistry.Register(item, [.. points]);
TreeExiting += () => GridRegistry.UnRegister(guid);
}
- StartPort.TryInsert(new TestItem() { PlaceHolderData = new() { ["temp"] = 0f } }, LaneSpan.Shifted(LaneSpan.One, 0), 0);
}
//ChatGPT Assisted
public BeltObstacle GetDistanceToNextItem(
@@ -458,22 +459,22 @@ public partial class TestItemConveyor : Node, IMovementConveyor
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);
+ // 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);
- }
- }
+ // }
+ // // 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)
{
diff --git a/src/VoxelGrid/VoxelGridNode.cs b/src/VoxelGrid/VoxelGridNode.cs
index 5dc6856..127ccc4 100644
--- a/src/VoxelGrid/VoxelGridNode.cs
+++ b/src/VoxelGrid/VoxelGridNode.cs
@@ -2,36 +2,90 @@ namespace ChickenGameTest;
using System;
using System.Collections.Generic;
-using System.Linq;
+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.Recipes;
using Godot;
-using Godot.Collections;
-using SJK.Functional;
+public class BacterialSystem : BaseSystem
+{
+ private QueryDescription _desc = new QueryDescription().WithAll();
+ public static Resources> Resources = new();
+ public BacterialSystem(World world) : base(world)
+ {
+
+ }
+ public override void Update(in float t)
+ {
+ var delta = t;
+ World.ParallelQuery(in _desc, (Entity entity, ref Bacteria bacteria, ref Temperature temperature) =>
+ {
+ var handle = bacteria.Data;
+ var data = Resources.Get(in handle);
+ for (int i = 0; i < data.Count; i++)
+ {
+ data[i] = data[i] with { Count = BacteriaModel.UpdatePopulation(data[i].Count, temperature.Celsius, delta) };
+ // GD.Print(data[i].Count);
+ if (data[i].Count <= 0.5)
+ {
+ data.RemoveAt(i);
+ i--;
+ }
+ }
+ });
+ }
+}
//Will Liklely be the game instead of a node like this
[Meta(typeof(IAutoNode))]// [Tool]
-public partial class VoxelGridNode : Node3D, IProvide, IProvide
+public partial class VoxelGridNode : Node3D, IProvide, IProvide, IProvide, IProvide, IProvide
{
public override void _Notification(int what) => this.Notify(what);
+ private World _world = default!;
+ World IProvide.Value() => _world;
private IVoxelGridRegistry _voxelGridRegistry = default!;
IVoxelGridRegistry IProvide.Value() => _voxelGridRegistry;
+ private IBlueprintManger _blueprintManger = default!;
+ IBlueprintManger IProvide.Value() => _blueprintManger;
+ private Recipes _recipes = default!;
+ IRecipes IProvide.Value() => _recipes;
private IItemRenderer _itemRenderer = default!;
IItemRenderer IProvide.Value() => _itemRenderer;
+ Group _systems;
public override void _Ready()
{
// GD.Print();
base._Ready();
_voxelGridRegistry = new VoxelRegistry();
- _itemRenderer = new TestItemRendered();
+ _itemRenderer = new ItemRenderSimple();
+ _blueprintManger = new BlueprintManger();
+ _recipes = new Recipes();
+ _world = World.Create();
+ _systems = new Group("Items", new BacterialSystem(_world));
+
+
AddChild(_itemRenderer as Node);
Timer timer = new Timer() { WaitTime = .25f, Autostart = true };//TEST
AddChild(timer);//TEST
// timer.Timeout += _itemRenderer.Tick;//TEST
+ timer.Timeout += () =>
+ {
+ _systems.BeforeUpdate(.25f);
+ _systems.Update(.25f);
+ _systems.AfterUpdate(.25f);
+ };
+ _systems.Initialize();
this.Provide();
}
+
+
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed("ui_up"))
@@ -46,4 +100,51 @@ public partial class VoxelGridNode : Node3D, IProvide, IProv
}
}
}
+ public override void _ExitTree()
+ {
+ base._ExitTree();
+ _systems.Dispose();
+ _world.Dispose();
+ }
+}
+public static class BacteriaModel
+{
+ // population = current bacteria count
+ // temperature = degrees Celsius
+ // deltaTime = elapsed time (hours)
+ public static double UpdatePopulation(
+ double population,
+ double temperature,
+ double deltaTime)
+ {
+ double rate;
+
+ // Very cold -> slight die-off
+ if (temperature <= 5)
+ {
+ rate = -0.1;
+ }
+ // Growth zone
+ else if (temperature < 35)
+ {
+ rate = 0.06 * (temperature - 5);
+ }
+ // Hot but still survivable
+ else if (temperature < 60)
+ {
+ rate = 1.8 - 0.08 * (temperature - 35);
+ }
+ // Dangerous heat -> bacteria die
+ else
+ {
+ rate = -0.8;
+ }
+
+ // Population update
+ double newPopulation =
+ population + (deltaTime * population * rate);
+
+ // Prevent negative bacteria counts
+ return Math.Max(0, newPopulation);
+ }
}
diff --git a/src/VoxelGrid/VoxelGridNode.tscn b/src/VoxelGrid/VoxelGridNode.tscn
index 722d5fd..28cbf1a 100644
--- a/src/VoxelGrid/VoxelGridNode.tscn
+++ b/src/VoxelGrid/VoxelGridNode.tscn
@@ -2,9 +2,12 @@
[ext_resource type="Script" uid="uid://dcrb286hmpli" path="res://src/VoxelGrid/VoxelGridNode.cs" id="1_tsdpe"]
[ext_resource type="Script" uid="uid://cnkblltup5guy" path="res://src/VoxelGrid/OvenTest.cs" id="3_r7dgx"]
+[ext_resource type="PackedScene" uid="uid://bktqs1lw6go4" path="res://src/VoxelGrid/ItemSpawner.tscn" id="5_mxaon"]
[ext_resource type="PackedScene" uid="uid://h00mq2srsbfa" path="res://assets/kenney_conveyor-kit/Models/GLB format/door.glb" id="5_wk2t5"]
[ext_resource type="Script" uid="uid://ee5aoxi8mjnw" path="res://src/VoxelGrid/BeltPort.cs" id="6_2wkfx"]
[ext_resource type="PackedScene" uid="uid://c4h7mwnfrdesg" path="res://src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn" id="6_mxaon"]
+[ext_resource type="Script" uid="uid://opbkqoaa7x2n" path="res://src/VoxelGrid/Balancer.cs" id="7_2wkfx"]
+[ext_resource type="Script" uid="uid://yec84plemjv1" path="res://src/VoxelGrid/SlicerTest.cs" id="8_2lg7i"]
[sub_resource type="Curve3D" id="Curve3D_mxaon"]
_data = {
@@ -13,6 +16,9 @@ _data = {
}
point_count = 2
+[sub_resource type="BoxMesh" id="BoxMesh_2wkfx"]
+size = Vector3(1, 1, 2)
+
[node name="VoxelGridNode" type="Node3D" unique_id=825696340]
script = ExtResource("1_tsdpe")
@@ -20,108 +26,123 @@ script = ExtResource("1_tsdpe")
transform = Transform3D(0.6279494, -0.32487354, 0.70720345, -8.896721e-09, 0.908705, 0.4174389, -0.77825415, -0.26213053, 0.5706208, 4.635174, 2.6038146, 2.739409)
[node name="ConveyorBeltStraight5" parent="." unique_id=975225936 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 3, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight22" parent="." unique_id=81137442 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 2, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight13" parent="." unique_id=607296315 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 0, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight26" parent="." unique_id=626657643 instance=ExtResource("6_mxaon")]
transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 1, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight6" parent="." unique_id=264656404 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -1, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight23" parent="." unique_id=1438072389 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -2, 0, 0)
-Width = 1
[node name="ConveyorBeltStraight14" parent="." unique_id=1045608025 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -4, 0, 0)
-Width = 1
-
-[node name="ConveyorBeltStraight27" parent="." unique_id=899289297 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -3, 0, 0)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 0, 0, 0)
[node name="ConveyorBeltStraight7" parent="." unique_id=1602707514 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 3, 0, 1)
-Width = 1
+transform = Transform3D(-1, 0, -8.742277e-08, 0, 1, 0, 8.742277e-08, 0, -1, 1, 0, 1)
+
+[node name="ConveyorBeltStraight8" parent="." unique_id=1032197109 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 1, 0, 2)
+
+[node name="ConveyorBeltStraight24" parent="." unique_id=574723066 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 1, 0, 6)
+
+[node name="ConveyorBeltStraight25" parent="." unique_id=1584944068 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 0, 0, 6)
+
+[node name="ConveyorBeltStraight13" parent="." unique_id=490179430 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 3, 0, 2)
+
+[node name="ConveyorBeltStraight20" parent="." unique_id=1684880263 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 4, 0, 2)
+
+[node name="ConveyorBeltStraight15" parent="." unique_id=1971663524 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 3, 0, 3)
+
+[node name="ConveyorBeltStraight23" parent="." unique_id=830278017 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 4, 0, 3)
[node name="ConveyorBeltStraight9" parent="." unique_id=1449572266 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 1)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 3, 0, 1)
+
+[node name="ConveyorBeltStraight26" parent="." unique_id=181268712 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 5)
+
+[node name="ConveyorBeltStraight27" parent="." unique_id=1546024538 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 6)
+
+[node name="ConveyorBeltStraight28" parent="." unique_id=1945842047 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 4)
+
+[node name="ConveyorBeltStraight29" parent="." unique_id=116753972 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 8)
+
+[node name="ConveyorBeltStraight30" parent="." unique_id=903050872 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 9)
+
+[node name="ConveyorBeltStraight31" parent="." unique_id=848458617 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 7)
+
+[node name="ConveyorBeltStraight32" parent="." unique_id=889036013 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 8)
+
+[node name="ConveyorBeltStraight33" parent="." unique_id=992629708 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 9)
+
+[node name="ConveyorBeltStraight34" parent="." unique_id=795974742 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 7, 0, 9)
+
+[node name="ConveyorBeltStraight35" parent="." unique_id=601890089 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 5)
+
+[node name="ConveyorBeltStraight36" parent="." unique_id=2134741630 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 7, 0, 4)
+
+[node name="ConveyorBeltStraight37" parent="." unique_id=196786809 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 4)
[node name="ConveyorBeltStraight10" parent="." unique_id=68139731 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 1)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 4, 0, 1)
[node name="ConveyorBeltStraight11" parent="." unique_id=358641682 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 7, 0, 1)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 5, 0, 1)
[node name="ConveyorBeltStraight12" parent="." unique_id=310565328 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 8, 0, 1)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 6, 0, 1)
[node name="ConveyorBeltStraight17" parent="." unique_id=111805683 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 9, 0, 1)
-Width = 1
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, 1)
+
+[node name="ConveyorBeltStraight21" parent="." unique_id=764425478 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, 2)
+
+[node name="ConveyorBeltStraight22" parent="." unique_id=1089887693 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, 3)
[node name="ConveyorBeltStraight18" parent="." unique_id=971476244 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 9, 0, 0)
-Width = 1
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, 0)
-[node name="ConveyorBeltStraight19" parent="." unique_id=87035771 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 9, 0, -1)
-Width = 1
+[node name="ConveyorBeltStraight19" parent="." unique_id=1940918727 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 8, 0, -3)
-[node name="ConveyorBeltStraight24" parent="." unique_id=904248251 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 2, 0, 1)
-Width = 1
+[node name="ConveyorBeltStraight40" parent="." unique_id=1578916497 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 8, 0, -2)
-[node name="ConveyorBeltStraight15" parent="." unique_id=533235542 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 0, 0, 1)
-Width = 1
+[node name="ConveyorBeltStraight41" parent="." unique_id=1562444632 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 8, 0, -4)
-[node name="ConveyorBeltStraight28" parent="." unique_id=2116943332 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 1, 0, 1)
-Width = 1
+[node name="ConveyorBeltStraight38" parent="." unique_id=1520289120 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, -3)
-[node name="ConveyorBeltStraight8" parent="." unique_id=1109978762 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -1, 0, 1)
-Width = 1
-
-[node name="ConveyorBeltStraight25" parent="." unique_id=1110001269 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -2, 0, 1)
-Width = 1
+[node name="ConveyorBeltStraight39" parent="." unique_id=44974977 instance=ExtResource("6_mxaon")]
+transform = Transform3D(1, 0, 1.7484555e-07, 0, 1, 0, -1.7484555e-07, 0, 1, 7, 0, -4)
[node name="ConveyorBeltStraight16" parent="." unique_id=1178816500 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -4, 0, 1)
-Width = 1
-
-[node name="ConveyorBeltStraight29" parent="." unique_id=1537356869 instance=ExtResource("6_mxaon")]
-transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, -3, 0, 1)
-Width = 1
+transform = Transform3D(1.3113416e-07, 0, -1, 0, 1, 0, 1, 0, 1.3113416e-07, 0, 0, 1)
[node name="OvenTest" type="Node3D" parent="." unique_id=824176002]
-transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 0)
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0)
script = ExtResource("3_r7dgx")
-[node name="Node3D2" type="Node3D" parent="OvenTest" unique_id=1815100025 node_paths=PackedStringArray("Path")]
+[node name="Node3D2" type="Node3D" parent="OvenTest" unique_id=1815100025]
transform = Transform3D(1.3113416e-07, 0, 1, 0, 1, 0, -1, 0, 1.3113416e-07, 0, 0, 0)
script = ExtResource("6_2wkfx")
Face = 4
Width = 1
-Access = 3
-Path = NodePath("Path3D")
+Access = 1
PortName = "Input"
[node name="Path3D" type="Path3D" parent="OvenTest/Node3D2" unique_id=1525648764]
@@ -130,13 +151,12 @@ curve = SubResource("Curve3D_mxaon")
[node name="door3" parent="OvenTest/Node3D2" unique_id=351624885 instance=ExtResource("5_wk2t5")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.870017e-08, 0, -0.6001501)
-[node name="Node3D3" type="Node3D" parent="OvenTest" unique_id=1033202746 node_paths=PackedStringArray("Path")]
+[node name="Node3D3" type="Node3D" parent="OvenTest" unique_id=1033202746]
transform = Transform3D(-2.1855693e-07, 0, -1, 0, 1, 0, 1, 0, -2.1855693e-07, 0, 0, 1)
script = ExtResource("6_2wkfx")
Face = 4
Width = 1
-Access = 3
-Path = NodePath("Path3D2")
+Access = 2
PortName = "OutPut"
[node name="Path3D2" type="Path3D" parent="OvenTest/Node3D3" unique_id=739562310]
@@ -144,3 +164,115 @@ curve = SubResource("Curve3D_mxaon")
[node name="door4" parent="OvenTest/Node3D3" unique_id=1602265662 instance=ExtResource("5_wk2t5")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.9604645e-08, 0, -0.3998499)
+
+[node name="door5" parent="OvenTest/Node3D3" unique_id=102838222 instance=ExtResource("5_wk2t5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.9604645e-08, 0, -0.3998499)
+
+[node name="ItemSpawner" parent="." unique_id=966349707 instance=ExtResource("5_mxaon")]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -1.0023941, 0, 0.0019463301)
+ItemName = "Potato"
+
+[node name="ItemSpawner2" parent="." unique_id=405829395 instance=ExtResource("5_mxaon")]
+transform = Transform3D(3.059797e-07, 0, -1, 0, 1, 0, 1, 0, 3.059797e-07, -1, 0, 1)
+ItemName = "Onion"
+
+[node name="ItemSpawner3" parent="." unique_id=422927887 instance=ExtResource("5_mxaon")]
+transform = Transform3D(3.059797e-07, 0, -1, 0, 1, 0, 1, 0, 3.059797e-07, -1, 0, 6)
+ItemName = "Potato"
+
+[node name="Balancer" type="Node3D" parent="." unique_id=619243985]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, 2)
+script = ExtResource("7_2wkfx")
+
+[node name="Node3D" type="Node3D" parent="Balancer" unique_id=793236513]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 0)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 1
+
+[node name="Node3D3" type="Node3D" parent="Balancer" unique_id=1846433120]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 0, 0, 0)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 2
+
+[node name="Node3D4" type="Node3D" parent="Balancer" unique_id=1579207766]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 0, 0, 1)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 1
+
+[node name="Node3D2" type="Node3D" parent="Balancer" unique_id=717100096]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 1)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 2
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Balancer" unique_id=383290173]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0.5)
+mesh = SubResource("BoxMesh_2wkfx")
+
+[node name="Balancer8" type="Node3D" parent="." unique_id=1783081047]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 7, 0, -1)
+script = ExtResource("7_2wkfx")
+
+[node name="Node3D" type="Node3D" parent="Balancer8" unique_id=1818940385]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 0)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 1
+
+[node name="Node3D3" type="Node3D" parent="Balancer8" unique_id=51764402]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 0, 0, 0)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 2
+
+[node name="Node3D4" type="Node3D" parent="Balancer8" unique_id=233486636]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 0, 0, 1)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 1
+
+[node name="Node3D2" type="Node3D" parent="Balancer8" unique_id=1446214840]
+transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 1)
+script = ExtResource("6_2wkfx")
+Face = 4
+Width = 1
+Access = 2
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Balancer8" unique_id=556689065]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0.5)
+mesh = SubResource("BoxMesh_2wkfx")
+
+[node name="Slicer" type="Node3D" parent="." unique_id=566544377]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 0, -2)
+script = ExtResource("8_2lg7i")
+
+[node name="Node3D4" type="Node3D" parent="Slicer" unique_id=1206144064]
+transform = Transform3D(-1, 0, 8.742277e-08, 0, 1, 0, -8.742277e-08, 0, -1, 0, 0, 0)
+
+[node name="Path3D" type="Path3D" parent="Slicer/Node3D4" unique_id=894348025]
+curve = SubResource("Curve3D_mxaon")
+
+[node name="door3" parent="Slicer/Node3D4" unique_id=1024066398 instance=ExtResource("5_wk2t5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.870017e-08, 0, -0.6001501)
+
+[node name="Node3D5" type="Node3D" parent="Slicer" unique_id=1113082191]
+transform = Transform3D(1, 0, -1.7484555e-07, 0, 1, 0, 1.7484555e-07, 0, 1, 0, 0, 0)
+
+[node name="Path3D2" type="Path3D" parent="Slicer/Node3D5" unique_id=1352328131]
+curve = SubResource("Curve3D_mxaon")
+
+[node name="door4" parent="Slicer/Node3D5" unique_id=1411233670 instance=ExtResource("5_wk2t5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.9604645e-08, 0, -0.3998499)
+
+[node name="door5" parent="Slicer/Node3D5" unique_id=770270315 instance=ExtResource("5_wk2t5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.9604645e-08, 0, -0.3998499)
diff --git a/src/VoxelGrid/VoxelRegistry.cs b/src/VoxelGrid/VoxelRegistry.cs
index fb8f3c6..50e3b2e 100644
--- a/src/VoxelGrid/VoxelRegistry.cs
+++ b/src/VoxelGrid/VoxelRegistry.cs
@@ -1,13 +1,9 @@
namespace ChickenGameTest;
-using Chickensoft.GodotNodeInterfaces;
-using Chickensoft.Introspection;
-using Chickensoft.AutoInject;
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
-using ChickenGameTest;
using SJK.Functional;
public interface IVoxelGridRegistry