namespace FoodFactory.Voxel; using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using Arch.Core; using Arch.LowLevel; using Arch.System; using Chickensoft.AutoInject; using Chickensoft.Introspection; using Chickensoft.SaveFileBuilder; using Chickensoft.Serialization; using Chickensoft.Serialization.Godot; using FoodFactory; using FoodFactory.Blueprints; using FoodFactory.Conveyors; using FoodFactory.Math; using FoodFactory.Recipes; using Godot; using SharpYaml; 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.Query(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, IProvide, IProvide, IProvide, IProvide//, // IProvide> { public override void _Notification(int what) => this.Notify(what); private IFoodFactoryApi _api = default!; IFoodFactoryApi IProvide.Value() => _api; 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; // public ISaveChunk Value() => SaveFile.Root; public static string SavePath => $"{OS.GetUserDataDir()}/SaveFile.json"; JsonSerializerOptions _options; public void Setup() { GodotSerialization.Setup(); _options = new JsonSerializerOptions { WriteIndented = true, TypeInfoResolver = new SerializableTypeResolver(), Converters = { new SerializableTypeConverter() } }; var test = "gg"; GD.Print(SavePath); // SaveFile = new SaveFile( // new SaveChunk( // onSave: (chunk) => // { // var gameData = new GameData() // { // World = _world, // // Equipments = chunk.GetChunkSaveData() // }; // return gameData; // }, // onLoad: (chunk, data) => // { // World.Destroy(_world); // _world = data.World; // // chunk.LoadChunkSaveData(data.Equipments); // } // ), // onSave: async data => // { // var yaml = JsonSerializer.Serialize(data, _options); // GD.Print(SavePath); // await File.WriteAllTextAsync(SavePath, yaml); // }, // onLoad: async () => // { // if (!File.Exists(SavePath)) // { // GD.PushWarning("Save does nto exist"); // return null; // } // var data = JsonSerializer.Deserialize(await File.ReadAllTextAsync(SavePath), _options); // return data; // } // ); } // public ISaveFile SaveFile { get; set; } = default!; Group _systems; public override void _Ready() { // GD.Print(); base._Ready(); _voxelGridRegistry = new VoxelRegistry(); _itemRenderer = new ItemRenderBuffered(); _blueprintManger = new BlueprintManger(); _recipes = new Recipes(); _world = World.Create(); _systems = new Group("Items", new BacterialSystem(_world)); var tickManger = new TickManger(); AddChild(_itemRenderer as Node); var delta = .2f; Timer timer = new Timer() { WaitTime = delta, Autostart = true };//TEST AddChild(timer);//TEST // timer.Timeout += _itemRenderer.Tick;//TEST _api = new FoodFactoryApi() { BlueprintManger = _blueprintManger, Recipes = _recipes, ItemRenderer = _itemRenderer, TickManger = tickManger, GridRegistry = _voxelGridRegistry }; int tick = 0; timer.Timeout += () => { _systems.BeforeUpdate(delta); _systems.Update(delta); _systems.AfterUpdate(delta); tickManger.BroadCast(new(tick, delta)); tick++; }; _systems.Initialize(); this.Provide(); } public override void _Input(InputEvent @event) { if (@event.IsActionPressed("ui_up")) { foreach (var item in GetChildren()) { if (item is ConveyorBeltStraight conveyor) { var node = conveyor.ConveyorLogic; node.IsReversed = !node.IsReversed; } } } if (@event.IsActionPressed("ui_right")) { // SaveFile.Save(); } if (@event.IsActionPressed("ui_left")) { // SaveFile.Load(); } } 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); } }