250 lines
6.5 KiB
C#
250 lines
6.5 KiB
C#
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<World, float>
|
|
{
|
|
private QueryDescription _desc = new QueryDescription().WithAll<Bacteria, Temperature>();
|
|
public static Resources<List<BacteriaData>> 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<IVoxelGridRegistry>,
|
|
IProvide<IItemRenderer>,
|
|
IProvide<IRecipes>,
|
|
IProvide<IBlueprintManger>,
|
|
IProvide<World>,
|
|
IProvide<IFoodFactoryApi>//,
|
|
// IProvide<ISaveChunk<GameData>>
|
|
{
|
|
public override void _Notification(int what) => this.Notify(what);
|
|
|
|
private IFoodFactoryApi _api = default!;
|
|
IFoodFactoryApi IProvide<IFoodFactoryApi>.Value() => _api;
|
|
private World _world = default!;
|
|
World IProvide<World>.Value() => _world;
|
|
private IVoxelGridRegistry _voxelGridRegistry = default!;
|
|
IVoxelGridRegistry IProvide<IVoxelGridRegistry>.Value() => _voxelGridRegistry;
|
|
private IBlueprintManger _blueprintManger = default!;
|
|
IBlueprintManger IProvide<IBlueprintManger>.Value() => _blueprintManger;
|
|
private Recipes _recipes = default!;
|
|
IRecipes IProvide<IRecipes>.Value() => _recipes;
|
|
private IItemRenderer _itemRenderer = default!;
|
|
IItemRenderer IProvide<IItemRenderer>.Value() => _itemRenderer;
|
|
// public ISaveChunk<GameData> 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<GameData>(
|
|
// new SaveChunk<GameData>(
|
|
// onSave: (chunk) =>
|
|
// {
|
|
|
|
// var gameData = new GameData()
|
|
// {
|
|
// World = _world,
|
|
// // Equipments = chunk.GetChunkSaveData<EquipmentsData>()
|
|
// };
|
|
// 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<GameData>(await File.ReadAllTextAsync(SavePath), _options);
|
|
// return data;
|
|
// }
|
|
// );
|
|
}
|
|
// public ISaveFile<GameData> SaveFile { get; set; } = default!;
|
|
Group<float> _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<float>("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);
|
|
}
|
|
}
|