Added a RTS camera, and some assorted changes.
This commit is contained in:
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "assets"]
|
||||
path = assets
|
||||
url = http://192.168.1.4:3000/Ronnie/FoodFactoryAssets
|
||||
url = https://gitea.superjrking.com/Ronnie/FoodFactoryAssets
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
<PackageReference Include="Arch.LowLevel" Version="1.1.5" />
|
||||
<PackageReference Include="Arch.System" Version="1.1.0" />
|
||||
<PackageReference Include="Chickensoft.GameTools" Version="3.1.18" />
|
||||
<PackageReference Include="GodotHelper" Version="0.0.2" />
|
||||
<!-- <PackageReference Include="LanguageExt.Core" Version="5.0.0-beta-77" /> -->
|
||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||
<PackageReference Include="NCalc.LambdaCompilation" Version="5.12.0" />
|
||||
<PackageReference Include="NCalcSync" Version="5.12.0" />
|
||||
|
||||
168
RTSCamera.cs
Executable file
168
RTSCamera.cs
Executable file
@@ -0,0 +1,168 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using SJK.Math;
|
||||
|
||||
public partial class RTSCamera : Node3D
|
||||
{
|
||||
[Export]
|
||||
public Camera3D camera;
|
||||
Vector3 positionStartPos;
|
||||
Vector3 positionOffsetPos;
|
||||
Vector3 lastTransalation;
|
||||
|
||||
Vector3 cameraTargetOffset;
|
||||
Action Update_CurrentFunc;
|
||||
|
||||
//Generic bookkeeping variables;
|
||||
Vector2 LastMousePostition;
|
||||
//Camera Dragging Bookkeeping variables
|
||||
Vector3 LastMouseGroundPlanePositon;
|
||||
//Camera Rotating Bookkeeping variables
|
||||
float CameraRotateSpeed = .5f;
|
||||
bool isDraging;
|
||||
public override void _Ready()
|
||||
{
|
||||
Update_CurrentFunc = Update_DetectModeStart;
|
||||
}
|
||||
void Update_DetectModeStart()
|
||||
{
|
||||
if (Input.IsActionJustPressed("move_mouse"))
|
||||
{
|
||||
//Mouse Left went Down
|
||||
//Does nothing basicly
|
||||
}
|
||||
else if (Input.IsActionPressed("move_mouse") && GetViewport().GetMousePosition() != LastMousePostition)
|
||||
{
|
||||
LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero;
|
||||
Update_CurrentFunc = Update_CameraDrag;
|
||||
Update_CurrentFunc();
|
||||
// GD.Print("1");
|
||||
}
|
||||
else if (Input.IsActionPressed("camera_rotate") && GetViewport().GetMousePosition() != LastMousePostition)
|
||||
{
|
||||
LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero;
|
||||
Update_CurrentFunc = Update_RotateCamera;
|
||||
Update_CurrentFunc();
|
||||
// GD.Print("2");
|
||||
}
|
||||
|
||||
}
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (Input.IsActionJustPressed("ui_cancel"))
|
||||
{
|
||||
CancelUpdateFunc();
|
||||
}
|
||||
GD.PrintS(positionStartPos,positionOffsetPos,lastTransalation,LastMouseGroundPlanePositon,LastMousePostition,cameraTargetOffset,scrollAmount);
|
||||
Update_CurrentFunc();
|
||||
Update_CameraScroll((float)delta);
|
||||
LastMousePostition = GetViewport().GetMousePosition();
|
||||
camera.Fov = Mathf.Lerp(camera.Fov, Mathf.Lerp(90, 50, (camera.Position.Y - 5) / (80 - 5)), (float)delta * 10);
|
||||
}
|
||||
void CancelUpdateFunc()
|
||||
{
|
||||
Update_CurrentFunc = Update_DetectModeStart;
|
||||
}
|
||||
void Update_CameraDrag()
|
||||
{
|
||||
if (Input.IsActionJustReleased("move_mouse"))
|
||||
{
|
||||
CancelUpdateFunc();
|
||||
}
|
||||
|
||||
var hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero;
|
||||
|
||||
|
||||
var diff = LastMouseGroundPlanePositon - hitpos;
|
||||
|
||||
GlobalTranslate(diff);
|
||||
LastMouseGroundPlanePositon = hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero;
|
||||
|
||||
}
|
||||
float scrollAmount;
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
scrollAmount += Input.IsActionJustReleased("mouse_scroll_up") ? 1 : 0;
|
||||
scrollAmount += Input.IsActionJustReleased("mouse_scroll_down") ? -1 : 0;
|
||||
if (@event is InputEventKey eventKey && eventKey.Keycode == Key.F)
|
||||
{
|
||||
GlobalPosition = Vector3.Zero;
|
||||
camera.Position = Vector3.Zero;
|
||||
CancelUpdateFunc();
|
||||
}
|
||||
}
|
||||
void Update_CameraScroll(float delta)
|
||||
{
|
||||
|
||||
// Zoom to scrollwheel
|
||||
// float scrollAmount = Input.IsActionJustReleased("mouse_scroll_up")?1:0;
|
||||
// scrollAmount += Input.IsActionJustReleased( "mouse_scroll_down")?-1:0;
|
||||
// GD.Print(scrollAmount);
|
||||
float minHeight = 2;
|
||||
float maxHeight = 30;
|
||||
// Move camera towards hitPos
|
||||
// var hitPos = camera.MouseToGroundPlane();
|
||||
// Vector3 dir = hitPos - camera.Translation;
|
||||
var dir = -camera.GlobalTransform.Basis.Z * .5f;
|
||||
|
||||
var p = camera.Position;
|
||||
|
||||
// Stop zooming out at a certain distance.
|
||||
// TODO: Maybe you should still slide around at 20 zoom?
|
||||
if (scrollAmount > 0 || p.Y < (maxHeight - 0.1f))
|
||||
{
|
||||
cameraTargetOffset += dir * scrollAmount;
|
||||
}
|
||||
DebugDraw3D.DrawArrow(Vector3.Zero,cameraTargetOffset);
|
||||
Vector3 lastCameraPosition = camera.Position;
|
||||
camera.Position = camera.Position.Lerp(camera.Position + cameraTargetOffset, delta);
|
||||
cameraTargetOffset -= camera.Position - lastCameraPosition;
|
||||
|
||||
p = camera.Position;
|
||||
if (p.Y < minHeight)
|
||||
{
|
||||
p.Y = minHeight;
|
||||
}
|
||||
if (p.Y > maxHeight)
|
||||
{
|
||||
p.Y = maxHeight;
|
||||
}
|
||||
|
||||
camera.Position = p;
|
||||
// Change camera angle
|
||||
camera.RotationDegrees = new Vector3(
|
||||
Mathf.Lerp(-50, -75, camera.Position.Y / maxHeight),
|
||||
camera.RotationDegrees.Y,
|
||||
camera.RotationDegrees.Z
|
||||
);
|
||||
scrollAmount = 0;
|
||||
}
|
||||
void Update_RotateCamera()
|
||||
{
|
||||
if (!Input.IsActionPressed("move_mouse"))
|
||||
{
|
||||
CancelUpdateFunc();
|
||||
}
|
||||
Vector2 hitpos = GetViewport().GetMousePosition();
|
||||
|
||||
Vector2 diff = LastMousePostition - hitpos;
|
||||
camera.RotationDegrees = new Vector3(
|
||||
camera.RotationDegrees.X,
|
||||
camera.RotationDegrees.Y + (diff.X * CameraRotateSpeed),
|
||||
camera.RotationDegrees.Z
|
||||
);
|
||||
LastMousePostition = hitpos = GetViewport().GetMousePosition();
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class SJKMath
|
||||
{
|
||||
public static Vector3? MouseToPlane(this Plane plane, Camera3D viewCamera, Vector2? mousePos = null)
|
||||
{
|
||||
var from = viewCamera.ProjectRayOrigin( mousePos ?? viewCamera.GetViewport().GetMousePosition());
|
||||
var normal = viewCamera.ProjectRayNormal(mousePos ?? viewCamera.GetViewport().GetMousePosition());
|
||||
return plane.IntersectsRay(from, normal);
|
||||
}
|
||||
public static Vector3? MouseToGroundPlane(this Camera3D viewCamera, Vector2? mousePos = null, float offset = 0) =>
|
||||
(Plane.PlaneXZ with { D = offset }).MouseToPlane(viewCamera, mousePos);
|
||||
}
|
||||
1
RTSCamera.cs.uid
Normal file
1
RTSCamera.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bdvwvdqrbks7c
|
||||
@@ -49,6 +49,74 @@ theme/default_font_multichannel_signed_distance_field=true
|
||||
theme/default_font_generate_mipmaps=true
|
||||
theme/default_theme_scale=2.0
|
||||
|
||||
[input]
|
||||
|
||||
move_forward={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_back={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_left={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
rotate_left={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
rotate_right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
camera_up={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
camera_down={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
place={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(97, 9),"global_position":Vector2(106, 57),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
mouse_scroll_up={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
mouse_scroll_down={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_mouse={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(88, 14),"global_position":Vector2(97, 62),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
camera_rotate={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":2,"position":Vector2(197, 20),"global_position":Vector2(206, 68),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="mobile"
|
||||
|
||||
1
src/Blueprints/BlueprintContext.cs.uid
Normal file
1
src/Blueprints/BlueprintContext.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cy4shmpf6ncqn
|
||||
1
src/Blueprints/BlueprintManger.cs.uid
Normal file
1
src/Blueprints/BlueprintManger.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvf8g3wbikopb
|
||||
1
src/Blueprints/CompiledBlueprint.cs.uid
Normal file
1
src/Blueprints/CompiledBlueprint.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://7ncdfun3kqil
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxtk4cn40072m
|
||||
@@ -0,0 +1 @@
|
||||
uid://dpgrony8su3im
|
||||
@@ -0,0 +1 @@
|
||||
uid://boar6ktwp2m1e
|
||||
@@ -0,0 +1 @@
|
||||
uid://cv0hsod03jmng
|
||||
1
src/Blueprints/Provider/DefaultValueProvider.cs.uid
Normal file
1
src/Blueprints/Provider/DefaultValueProvider.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://croijjg1q3ui3
|
||||
1
src/Blueprints/Provider/FactoryCompiledNode.cs.uid
Normal file
1
src/Blueprints/Provider/FactoryCompiledNode.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ds3aflbt1maj5
|
||||
1
src/Blueprints/Provider/IValueProvider.cs.uid
Normal file
1
src/Blueprints/Provider/IValueProvider.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bp0bhlpk25uh8
|
||||
1
src/Blueprints/Provider/StaticCompiledNode.cs.uid
Normal file
1
src/Blueprints/Provider/StaticCompiledNode.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2srbqlc7hyo8
|
||||
1
src/Core/Components/Converters/TagConverter.cs.uid
Normal file
1
src/Core/Components/Converters/TagConverter.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cgs4d1j3i5ua6
|
||||
1
src/Core/Components/Converters/TagsConverter.cs.uid
Normal file
1
src/Core/Components/Converters/TagsConverter.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dqn40oryt7yyt
|
||||
6
src/Core/Direction.cs
Normal file
6
src/Core/Direction.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace FoodFactory.Core;
|
||||
|
||||
public enum Direction
|
||||
{
|
||||
Up, Down, Left, Right, Front, Back
|
||||
}
|
||||
1
src/Core/Direction.cs.uid
Normal file
1
src/Core/Direction.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://5eaay872p2wp
|
||||
48
src/Core/DirectionExtension.cs
Normal file
48
src/Core/DirectionExtension.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace FoodFactory.Core;
|
||||
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public static class DirectionExtension
|
||||
{
|
||||
public static Vector3I ToVector(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Vector3I.Up,
|
||||
Direction.Down => Vector3I.Down,
|
||||
Direction.Left => Vector3I.Left,
|
||||
Direction.Right => Vector3I.Right,
|
||||
Direction.Front => Vector3I.Forward,
|
||||
Direction.Back => Vector3I.Back,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction Reverse(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Down,
|
||||
Direction.Down => Direction.Up,
|
||||
Direction.Left => Direction.Right,
|
||||
Direction.Right => Direction.Left,
|
||||
Direction.Front => Direction.Back,
|
||||
Direction.Back => Direction.Front,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction RotateClockWise(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Up,
|
||||
Direction.Down => Direction.Down,
|
||||
Direction.Left => Direction.Back,
|
||||
Direction.Right => Direction.Front,
|
||||
Direction.Front => Direction.Right,
|
||||
Direction.Back => Direction.Left,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction RotateCounterClockWise(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Up,
|
||||
Direction.Down => Direction.Down,
|
||||
Direction.Right => Direction.Front,
|
||||
Direction.Left => Direction.Back,
|
||||
Direction.Back => Direction.Right,
|
||||
Direction.Front => Direction.Left,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
}
|
||||
1
src/Core/DirectionExtension.cs.uid
Normal file
1
src/Core/DirectionExtension.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bdyaesjr6l4c4
|
||||
1
src/Core/Registry.cs.uid
Normal file
1
src/Core/Registry.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dfal5nypn22nt
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory.Conveyors;
|
||||
using FoodFactory.Core;
|
||||
using FoodFactory.Items;
|
||||
using FoodFactory.Math;
|
||||
using FoodFactory.Voxel;
|
||||
|
||||
15
src/Equipment/EquipmentEntry.cs
Normal file
15
src/Equipment/EquipmentEntry.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace FoodFactory.Equipment;
|
||||
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.Serialization;
|
||||
using Godot;
|
||||
// [Tool]
|
||||
[Meta, Id("equipment_entry")]
|
||||
public partial class EquipmentEntry : Resource
|
||||
{
|
||||
[Export] public PackedScene VisualScene { get; set; }
|
||||
[Save("scene_path")] public string ScenePath { get => VisualScene.ResourcePath; set => VisualScene = GD.Load<PackedScene>(value); }
|
||||
[Export, Save("name")] public string Name { get; set; } = "";
|
||||
[Export, Save("id")] public string ID { get; set; } = "";
|
||||
[Export, Save("cost")] public int Cost { get; set; } = default;
|
||||
}
|
||||
1
src/Equipment/EquipmentEntry.cs.uid
Normal file
1
src/Equipment/EquipmentEntry.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://x8adhd57sup8
|
||||
47
src/Equipment/EquipmentManger.cs
Normal file
47
src/Equipment/EquipmentManger.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace FoodFactory.Equipment;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Godot;
|
||||
using SJK.Functional;
|
||||
|
||||
public interface IEquipmentManager
|
||||
{
|
||||
IEnumerable<EquipmentMetaData> GetEquipments();
|
||||
public Option<EquipmentId> Add(Node node, EquipmentEntry entry);
|
||||
}
|
||||
public class EquipmentManger : IEquipmentManager
|
||||
{
|
||||
private readonly Dictionary<string, EquipmentEntry> _equipmentEntrys = new();
|
||||
private readonly Dictionary<EquipmentId, EquipmentMetaData> _equipment = new();
|
||||
public Option<EquipmentId> Add(Node node, EquipmentEntry entry)
|
||||
{
|
||||
var metaData = new EquipmentMetaData(Guid.NewGuid(), node){ Entry = entry };
|
||||
node.TreeExiting += () =>
|
||||
{
|
||||
_equipment.Remove(metaData.Id);
|
||||
};
|
||||
_equipment.Add(metaData.Id,metaData);
|
||||
return Option<EquipmentId>.Some(metaData.Id);
|
||||
}
|
||||
public Option<EquipmentMetaData> GetEquipmentMetaData(EquipmentId id) => _equipment.GetValue(id).ToStructOption();
|
||||
public void Free(EquipmentId id) => GetEquipmentMetaData(id).ToClassOption().IfSome(some => some.Node.QueueFree());
|
||||
public IEnumerable<EquipmentMetaData> GetEquipments() =>_equipment.Values;
|
||||
}
|
||||
public class EquipmentMetaData
|
||||
{
|
||||
public EquipmentId Id { get; }
|
||||
public Node Node { get; }
|
||||
public required EquipmentEntry Entry { get; init;}
|
||||
public EquipmentMetaData(EquipmentId id, Node node)
|
||||
{
|
||||
Id = id;
|
||||
Node = node;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly record struct EquipmentId(Guid Id)
|
||||
{
|
||||
public static implicit operator EquipmentId(Guid id) => new(id);
|
||||
}
|
||||
1
src/Equipment/EquipmentManger.cs.uid
Normal file
1
src/Equipment/EquipmentManger.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2h6dtjopa53w
|
||||
@@ -6,6 +6,7 @@ using Arch.Core;
|
||||
using Arch.Core.Extensions;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.SaveFileBuilder;
|
||||
using FoodFactory.Conveyors;
|
||||
using FoodFactory.Core.Components;
|
||||
using FoodFactory.Items;
|
||||
@@ -52,7 +53,6 @@ public partial class OvenTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
|
||||
}
|
||||
_guid = GridRegistry.Register(this, VoxelTransform.Origin);
|
||||
this.Provide();
|
||||
|
||||
// var time = new Timer() { Autostart = true, OneShot = false, WaitTime = .1 };
|
||||
// AddChild(time);
|
||||
|
||||
@@ -69,7 +69,6 @@ public partial class OvenTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
|
||||
}
|
||||
temp.Kelvin += new TemperatureDelta(5f, TemperatureUnit.Fahrenheit).KelvinDelta;
|
||||
_itemBeingHeld.Set(temp);
|
||||
|
||||
Span<Entity> items = [_itemBeingHeld];
|
||||
var context = new RecipeContext(World.Worlds[0], items);
|
||||
var builder = new RecipeResultBuilder(stackalloc bool[10], new ItemBuilder[10]);
|
||||
@@ -116,7 +115,27 @@ public partial class OvenTest : Node3D, IProvide<IBeltPortHost>, IProvide<IVoxel
|
||||
GridRegistry.UnRegister(_guid);
|
||||
base._ExitTree();
|
||||
}
|
||||
// [Meta, Id("equipment_oven_data")]
|
||||
// public partial record OvenData(GridTransform3D GridTransform3D, Entity HeldItem) : EquipmentData
|
||||
// {
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class DelegateInsertBeltItemLogic : IBeltItemInsertLogic
|
||||
{
|
||||
private readonly Func<IBeltPort, IBeltItem, bool> _canAccept;
|
||||
|
||||
@@ -2,6 +2,7 @@ namespace FoodFactory;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -12,7 +13,9 @@ using Arch.LowLevel;
|
||||
using Arch.Persistence;
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.SaveFileBuilder;
|
||||
using Chickensoft.Serialization;
|
||||
using FoodFactory.Core.Components;
|
||||
using FoodFactory.Equipment;
|
||||
using FoodFactory.Items;
|
||||
using FoodFactory.Math;
|
||||
using FoodFactory.Recipes;
|
||||
@@ -20,7 +23,6 @@ using Godot;
|
||||
using SharpYaml;
|
||||
using SharpYaml.Serialization;
|
||||
using Utf8Json;
|
||||
|
||||
public class Test
|
||||
{
|
||||
|
||||
@@ -29,8 +31,6 @@ public class Test
|
||||
using var world = World.Create();
|
||||
|
||||
|
||||
var bucket = new BucketStorage<List<Entity>>();
|
||||
|
||||
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()));
|
||||
|
||||
@@ -46,22 +46,22 @@ public class Test
|
||||
{
|
||||
pizza.Get<Temperature>().Kelvin += .1f;
|
||||
}
|
||||
pizza.Add(new IngredientOf(turkey));
|
||||
// pizza.Add(new IngredientOf(turkey));
|
||||
var a = new List<Entity>() { pizza };
|
||||
|
||||
turkey.Add(new LayeredStack(bucket.Add(a)));
|
||||
turkey.Add(new LayeredStack2(a));
|
||||
// turkey.Add(new LayeredStack(bucket.Add(a)));
|
||||
// turkey.Add(new LayeredStack2(a));
|
||||
|
||||
|
||||
var list = bucket.GetRef(turkey.Get<LayeredStack>().Handle);
|
||||
GD.Print(string.Join(',', list));
|
||||
// var list = bucket.GetRef(turkey.Get<LayeredStack>().Handle);
|
||||
// GD.Print(string.Join(',', list));
|
||||
|
||||
var list2 = turkey.Get<LayeredStack2>().Children;
|
||||
turkey.Get<LayeredStack2>().Children.Add(turkey);
|
||||
GD.Print(string.Join(',', list2));
|
||||
var r = pizza.Get(typeof(Name));
|
||||
ComponentRegistry.TryGet<LayeredStack2>(out var type);
|
||||
GD.Print(type);
|
||||
// var list2 = turkey.Get<LayeredStack2>().Children;
|
||||
// turkey.Get<LayeredStack2>().Children.Add(turkey);
|
||||
// GD.Print(string.Join(',', list2));
|
||||
// var r = pizza.Get(typeof(Name));
|
||||
// ComponentRegistry.TryGet<LayeredStack2>(out var type);
|
||||
// GD.Print(type);
|
||||
|
||||
var flour = world.Create(new Name("flour"), new Temperature(71, TemperatureUnit.Fahrenheit), new Tags("flour", "wheat"));
|
||||
// var tag2 = new Tags();
|
||||
@@ -80,6 +80,7 @@ public class Test
|
||||
GD.Print(item.Namespace);
|
||||
GD.Print(item.FullName);
|
||||
}
|
||||
|
||||
string yaml = @"
|
||||
Id: potato_raw
|
||||
|
||||
@@ -104,23 +105,23 @@ public class Test
|
||||
var options = new YamlSerializerOptions()
|
||||
{
|
||||
// Converters = [new Recipes.DataNodeSerlicer()]
|
||||
// PolymorphismOptions = new YamlPolymorphismOptions
|
||||
// {
|
||||
// DerivedTypeMappings =
|
||||
// {
|
||||
// [typeof(DataNode)] =
|
||||
// [
|
||||
// new YamlDerivedType(typeof(SequenceNode), "sequence"){Tag = "!sequence"},
|
||||
// new YamlDerivedType(typeof(MappingNode), "mapping"){Tag = "!mapping"},
|
||||
// new YamlDerivedType(typeof(ValueNode), "value"){Tag = "!value"}
|
||||
// ],
|
||||
// [typeof(object)] =
|
||||
// [
|
||||
// new YamlDerivedType(typeof(Temperature), "temperature") { Tag = "!temperature"}
|
||||
// ]
|
||||
// PolymorphismOptions = new YamlPolymorphismOptions
|
||||
// {
|
||||
// DerivedTypeMappings =
|
||||
// {
|
||||
// [typeof(DataNode)] =
|
||||
// [
|
||||
// new YamlDerivedType(typeof(SequenceNode), "sequence"){Tag = "!sequence"},
|
||||
// new YamlDerivedType(typeof(MappingNode), "mapping"){Tag = "!mapping"},
|
||||
// new YamlDerivedType(typeof(ValueNode), "value"){Tag = "!value"}
|
||||
// ],
|
||||
// [typeof(object)] =
|
||||
// [
|
||||
// new YamlDerivedType(typeof(Temperature), "temperature") { Tag = "!temperature"}
|
||||
// ]
|
||||
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
};
|
||||
// var test = YamlSerializer.Serialize(new ItemData()
|
||||
// {
|
||||
@@ -290,114 +291,38 @@ public record struct MicroNutrients(List<Vitamin> Vitamins);
|
||||
|
||||
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<Entity> Children);
|
||||
// public record struct IngredientOf(Entity Source);
|
||||
// public record struct LayeredStack(Handle Handle);
|
||||
// public record struct LayeredStack2(List<Entity> Children);
|
||||
|
||||
public record struct Bacteria(Handle<List<BacteriaData>> Data);
|
||||
public record struct BacteriaData(string Name, double Count);
|
||||
|
||||
public record struct Handle(int Index, int Version);
|
||||
|
||||
public class BucketStorage<T>
|
||||
{
|
||||
private struct Slot
|
||||
{
|
||||
public T Value;
|
||||
public int Version;
|
||||
public bool Occupied;
|
||||
}
|
||||
|
||||
private Slot[] _slots = new Slot[1];
|
||||
private Stack<int> _freeIndices = new();
|
||||
|
||||
// Allocate a new slot
|
||||
public Handle Add(T value)
|
||||
{
|
||||
if (_freeIndices.Count > 0)
|
||||
{
|
||||
int index = _freeIndices.Pop();
|
||||
var slot = _slots[index];
|
||||
|
||||
slot.Value = value;
|
||||
slot.Occupied = true;
|
||||
slot.Version++; // bump version on reuse
|
||||
|
||||
_slots[index] = slot;
|
||||
|
||||
return new Handle { Index = index, Version = slot.Version };
|
||||
}
|
||||
else
|
||||
{
|
||||
var slot = new Slot
|
||||
{
|
||||
Value = value,
|
||||
Version = 1,
|
||||
Occupied = true
|
||||
};
|
||||
System.Array.Resize(ref _slots, _slots.Length + 1);
|
||||
_slots[^1] = slot;
|
||||
|
||||
return new Handle
|
||||
{
|
||||
Index = _slots.Length - 1,
|
||||
Version = slot.Version
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Safe access
|
||||
public bool TryGet(Handle handle, out T value)
|
||||
{
|
||||
if (handle.Index < 0 || handle.Index >= _slots.Length)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var slot = _slots[handle.Index];
|
||||
|
||||
if (!slot.Occupied || slot.Version != handle.Version)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = slot.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Direct (unsafe-ish) access if you trust the handle
|
||||
public ref T GetRef(Handle handle)
|
||||
{
|
||||
return ref _slots[handle.Index].Value;
|
||||
}
|
||||
|
||||
// Remove and recycle index
|
||||
public bool Remove(Handle handle)
|
||||
{
|
||||
if (handle.Index < 0 || handle.Index >= _slots.Length)
|
||||
return false;
|
||||
|
||||
var slot = _slots[handle.Index];
|
||||
|
||||
if (!slot.Occupied || slot.Version != handle.Version)
|
||||
return false;
|
||||
|
||||
slot.Occupied = false;
|
||||
slot.Version++; // invalidate old handles
|
||||
|
||||
_slots[handle.Index] = slot;
|
||||
_freeIndices.Push(handle.Index);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Meta, Id("game_data")]
|
||||
public partial record GameData
|
||||
{
|
||||
[Save("world_data")]
|
||||
public required World World { get; init; }
|
||||
// [Save("equipments_data")]
|
||||
// public required Dictionary<EquipmentId, EquipmentData> Equipments { get; init; }
|
||||
// public required EquipmentsData Equipments { get; init; }//TempTest /\
|
||||
}
|
||||
// [Meta, Id("equipments_data")]
|
||||
// public partial record EquipmentsData
|
||||
// {
|
||||
|
||||
// [Save("world_data")]
|
||||
// public required Dictionary<EquipmentId, EquipmentData> Equipments { get; init; }
|
||||
// }
|
||||
|
||||
[Meta, Id("equipment_data")]
|
||||
public abstract partial record EquipmentData
|
||||
{
|
||||
|
||||
[Save("guid_data")]
|
||||
public required EquipmentId Id { get; init; }
|
||||
}
|
||||
|
||||
253
src/VoxelGrid/ItemPlacerTest.cs
Normal file
253
src/VoxelGrid/ItemPlacerTest.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
namespace FoodFactory;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using FoodFactory.Equipment;
|
||||
using Godot;
|
||||
using GodotHelpers.Raycasts;
|
||||
using SJK.Math;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ItemPlacerTest : Node
|
||||
{
|
||||
[Export] public string PlaceAction { get; set; } = "";
|
||||
|
||||
[Export] public float Length { get; set; } = 10f;
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Export] public EquipmentEntry[] EquipmentEntrys { get; set; } = [];
|
||||
|
||||
|
||||
private InputGestureManager _inputThing = default!;
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
_inputThing = new InputGestureManager.Builder()
|
||||
.AddAction(PlaceAction)
|
||||
.HoldTime(0.1f)
|
||||
.OnQuickPress(TryPlaceItem)
|
||||
.BuildAction()
|
||||
.Build();
|
||||
|
||||
}
|
||||
public void TryPlaceItem()
|
||||
{
|
||||
var camera = GetViewport().GetCamera3D();
|
||||
|
||||
var space = camera.GetWorld3D().DirectSpaceState;
|
||||
var orgin = camera.ProjectRayOrigin(GetViewport().GetMousePosition());
|
||||
var to = camera.ProjectRayNormal(GetViewport().GetMousePosition());
|
||||
var result = space.RaycastEx(orgin, orgin + to * Length);
|
||||
if (result is not null)
|
||||
{
|
||||
DebugDraw3D.DrawLine(orgin, result.Position, Colors.Red, 1);
|
||||
var rounderPos = new Vector3I(Mathf.RoundToInt(result.Position.X), Mathf.RoundToInt(result.Position.Y), Mathf.RoundToInt(result.Position.Z));
|
||||
DebugDraw3D.DrawBox(rounderPos, Quaternion.Identity, Vector3.One, Colors.Blue, true, 1);
|
||||
var instance = EquipmentEntrys[0].VisualScene.Instantiate<Node3D>();
|
||||
instance.Position = rounderPos;
|
||||
GetParent().GetParent().AddChild(instance);
|
||||
}
|
||||
}
|
||||
public override void _UnhandledInput(InputEvent @event) => _inputThing.HandleInput(@event);
|
||||
public override void _Process(double delta) => _inputThing.Update((float)delta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public sealed class InputGestureManager
|
||||
{
|
||||
private readonly Dictionary<string, GestureBinding> _bindings;
|
||||
|
||||
private InputGestureManager(Dictionary<string, GestureBinding> bindings)
|
||||
{
|
||||
_bindings = bindings;
|
||||
}
|
||||
|
||||
public void HandleInput(InputEvent inputEvent)
|
||||
{
|
||||
foreach (var binding in _bindings.Values)
|
||||
{
|
||||
binding.HandleInput(inputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
foreach (var binding in _bindings.Values)
|
||||
{
|
||||
binding.Update(delta);
|
||||
}
|
||||
}
|
||||
|
||||
#region Builder
|
||||
|
||||
public sealed class Builder
|
||||
{
|
||||
private readonly Dictionary<string, GestureBinding> _bindings = new();
|
||||
|
||||
public GestureBuilder AddAction(string actionName)
|
||||
{
|
||||
var binding = new GestureBinding(actionName);
|
||||
|
||||
return new GestureBuilder(
|
||||
this,
|
||||
binding,
|
||||
completed => _bindings[actionName] = completed);
|
||||
}
|
||||
|
||||
public InputGestureManager Build() => new(_bindings);
|
||||
}
|
||||
|
||||
public sealed class GestureBuilder
|
||||
{
|
||||
private readonly Builder _parent;
|
||||
private readonly GestureBinding _binding;
|
||||
private readonly Action<GestureBinding> _onComplete;
|
||||
|
||||
internal GestureBuilder(
|
||||
Builder parent,
|
||||
GestureBinding binding,
|
||||
Action<GestureBinding> onComplete)
|
||||
{
|
||||
_parent = parent;
|
||||
_binding = binding;
|
||||
_onComplete = onComplete;
|
||||
}
|
||||
|
||||
public GestureBuilder HoldTime(float seconds)
|
||||
{
|
||||
_binding.HoldThreshold = seconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder Predicate(Func<bool> predicate)
|
||||
{
|
||||
_binding.Predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder OnQuickPress(Action callback)
|
||||
{
|
||||
_binding.OnQuickPress = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder OnHoldStart(Action callback)
|
||||
{
|
||||
_binding.OnHoldStart = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder OnHolding(Action<float> callback)
|
||||
{
|
||||
_binding.OnHolding = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder OnDrag(Action<Vector2> callback)
|
||||
{
|
||||
_binding.OnDrag = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GestureBuilder OnRelease(Action callback)
|
||||
{
|
||||
_binding.OnRelease = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder BuildAction()
|
||||
{
|
||||
_onComplete(_binding);
|
||||
return _parent;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal sealed class GestureBinding
|
||||
{
|
||||
public string ActionName { get; }
|
||||
|
||||
public float HoldThreshold = 0.25f;
|
||||
|
||||
public Func<bool>? Predicate;
|
||||
|
||||
public Action? OnQuickPress;
|
||||
public Action? OnHoldStart;
|
||||
public Action<float>? OnHolding;
|
||||
public Action<Vector2>? OnDrag;
|
||||
public Action? OnRelease;
|
||||
|
||||
private bool _pressed;
|
||||
private bool _holding;
|
||||
private float _heldTime;
|
||||
|
||||
public GestureBinding(string actionName)
|
||||
{
|
||||
ActionName = actionName;
|
||||
}
|
||||
|
||||
public void HandleInput(InputEvent inputEvent)
|
||||
{
|
||||
if (Predicate != null && !Predicate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputEvent.IsActionPressed(ActionName))
|
||||
{
|
||||
_pressed = true;
|
||||
_holding = false;
|
||||
_heldTime = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputEvent.IsActionReleased(ActionName))
|
||||
{
|
||||
if (_holding)
|
||||
{
|
||||
OnRelease?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnQuickPress?.Invoke();
|
||||
}
|
||||
|
||||
_pressed = false;
|
||||
_holding = false;
|
||||
_heldTime = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_holding &&
|
||||
inputEvent is InputEventMouseMotion motion)
|
||||
{
|
||||
OnDrag?.Invoke(motion.Relative);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
if (!_pressed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_heldTime += delta;
|
||||
|
||||
if (!_holding &&
|
||||
_heldTime >= HoldThreshold)
|
||||
{
|
||||
_holding = true;
|
||||
OnHoldStart?.Invoke();
|
||||
}
|
||||
|
||||
if (_holding)
|
||||
{
|
||||
OnHolding?.Invoke(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/VoxelGrid/ItemPlacerTest.cs.uid
Normal file
1
src/VoxelGrid/ItemPlacerTest.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://0yvk53xc1dix
|
||||
149
src/VoxelGrid/RTSCameraController.cs
Normal file
149
src/VoxelGrid/RTSCameraController.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
namespace FoodFactory;
|
||||
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class RTSCameraController : Node3D
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Export] public float MoveSpeed = 20f;
|
||||
[Export] public float RotationSpeed = 90f;
|
||||
[Export] public float ZoomSpeed = 5f;
|
||||
[Export] public float MinZoom = 5f;
|
||||
[Export] public float MaxZoom = 50f;
|
||||
[Export] public float HeightSpeed = 10f;
|
||||
|
||||
[Node("YawPivot")]
|
||||
private Node3D _yawPivot{get;set;} = default!;
|
||||
[Node("YawPivot/PitchPivent")]
|
||||
private Node3D _pitchPivot{get;set;} = default!;
|
||||
[Node("YawPivot/PitchPivent/Camera3D")]
|
||||
private Camera3D _camera{get;set;} = default!;
|
||||
|
||||
private float _zoomDistance = 20f;
|
||||
|
||||
private bool _freeLook = false;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// _yawPivot = GetNode<Node3D>("YawPivot");
|
||||
// _pitchPivot = _yawPivot.GetNode<Node3D>("PitchPivot");
|
||||
// _camera = _pitchPivot.GetNode<Camera3D>("Camera3D");
|
||||
|
||||
UpdateZoom();
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
float dt = (float)delta;
|
||||
|
||||
HandleMovement(dt);
|
||||
HandleRotation(dt);
|
||||
HandleHeight(dt);
|
||||
}
|
||||
|
||||
private void HandleMovement(float dt)
|
||||
{
|
||||
Vector3 move = Vector3.Zero;
|
||||
|
||||
if (Input.IsActionPressed("move_forward"))
|
||||
move -= _yawPivot.GlobalBasis.Z;
|
||||
|
||||
if (Input.IsActionPressed("move_back"))
|
||||
move += _yawPivot.GlobalBasis.Z;
|
||||
|
||||
if (Input.IsActionPressed("move_left"))
|
||||
move -= _yawPivot.GlobalBasis.X;
|
||||
|
||||
if (Input.IsActionPressed("move_right"))
|
||||
move += _yawPivot.GlobalBasis.X;
|
||||
|
||||
move.Y = 0;
|
||||
move = move.Normalized();
|
||||
|
||||
GlobalPosition += move * MoveSpeed * dt;
|
||||
}
|
||||
|
||||
private void HandleRotation(float dt)
|
||||
{
|
||||
if (Input.IsActionPressed("rotate_left"))
|
||||
RotateY(Mathf.DegToRad(RotationSpeed * dt));
|
||||
|
||||
if (Input.IsActionPressed("rotate_right"))
|
||||
RotateY(Mathf.DegToRad(-RotationSpeed * dt));
|
||||
}
|
||||
|
||||
private void HandleHeight(float dt)
|
||||
{
|
||||
Vector3 pos = GlobalPosition;
|
||||
|
||||
if (Input.IsActionPressed("camera_up"))
|
||||
pos.Y += HeightSpeed * dt;
|
||||
|
||||
if (Input.IsActionPressed("camera_down"))
|
||||
pos.Y -= HeightSpeed * dt;
|
||||
|
||||
GlobalPosition = pos;
|
||||
}
|
||||
|
||||
private void UpdateZoom()
|
||||
{
|
||||
_camera.Position = new Vector3(0, 0, _zoomDistance);
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (@event is InputEventMouseButton mouseButton)
|
||||
{
|
||||
if (mouseButton.ButtonIndex == MouseButton.WheelUp)
|
||||
{
|
||||
_zoomDistance -= ZoomSpeed;
|
||||
_zoomDistance = Mathf.Clamp(
|
||||
_zoomDistance,
|
||||
MinZoom,
|
||||
MaxZoom
|
||||
);
|
||||
|
||||
UpdateZoom();
|
||||
}
|
||||
|
||||
if (mouseButton.ButtonIndex == MouseButton.WheelDown)
|
||||
{
|
||||
_zoomDistance += ZoomSpeed;
|
||||
_zoomDistance = Mathf.Clamp(
|
||||
_zoomDistance,
|
||||
MinZoom,
|
||||
MaxZoom
|
||||
);
|
||||
|
||||
UpdateZoom();
|
||||
}
|
||||
|
||||
if (mouseButton.ButtonIndex == MouseButton.Middle)
|
||||
{
|
||||
_freeLook = mouseButton.Pressed;
|
||||
}
|
||||
}
|
||||
|
||||
if (_freeLook && @event is InputEventMouseMotion motion)
|
||||
{
|
||||
_yawPivot.RotateY(
|
||||
Mathf.DegToRad(-motion.Relative.X * 0.2f)
|
||||
);
|
||||
|
||||
Vector3 rot = _pitchPivot.Rotation;
|
||||
|
||||
rot.X += Mathf.DegToRad(-motion.Relative.Y * 0.2f);
|
||||
|
||||
rot.X = Mathf.Clamp(
|
||||
rot.X,
|
||||
Mathf.DegToRad(-80),
|
||||
Mathf.DegToRad(-15)
|
||||
);
|
||||
|
||||
_pitchPivot.Rotation = rot;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/VoxelGrid/RTSCameraController.cs.uid
Normal file
1
src/VoxelGrid/RTSCameraController.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://wlid36cxbse0
|
||||
15
src/VoxelGrid/RtsController.tscn
Normal file
15
src/VoxelGrid/RtsController.tscn
Normal file
@@ -0,0 +1,15 @@
|
||||
[gd_scene format=3 uid="uid://dr5gfg25sjr04"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bdvwvdqrbks7c" path="res://RTSCamera.cs" id="1_0un4r"]
|
||||
|
||||
[node name="RTS" type="Node3D" unique_id=1383983755 node_paths=PackedStringArray("camera")]
|
||||
script = ExtResource("1_0un4r")
|
||||
camera = NodePath("Camera3D")
|
||||
|
||||
[node name="YawPivot" type="Node3D" parent="." unique_id=1634769952]
|
||||
|
||||
[node name="PitchPivent" type="Node3D" parent="YawPivot" unique_id=1035768574]
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=938232118]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.8646082, 0.5024466, 0, -0.5024466, 0.8646082, 1.1920929e-07, 1.8606924, 2.2873116)
|
||||
current = true
|
||||
@@ -2,17 +2,24 @@ 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>();
|
||||
@@ -44,7 +51,14 @@ public class BacterialSystem : BaseSystem<World, float>
|
||||
|
||||
//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>
|
||||
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);
|
||||
|
||||
@@ -60,6 +74,62 @@ public partial class VoxelGridNode : Node3D, IProvide<IVoxelGridRegistry>, IProv
|
||||
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()
|
||||
{
|
||||
@@ -118,6 +188,15 @@ public partial class VoxelGridNode : Node3D, IProvide<IVoxelGridRegistry>, IProv
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@event.IsActionPressed("ui_right"))
|
||||
{
|
||||
SaveFile.Save();
|
||||
|
||||
}
|
||||
if (@event.IsActionPressed("ui_left"))
|
||||
{
|
||||
SaveFile.Load();
|
||||
}
|
||||
}
|
||||
public override void _ExitTree()
|
||||
{
|
||||
@@ -125,6 +204,7 @@ public partial class VoxelGridNode : Node3D, IProvide<IVoxelGridRegistry>, IProv
|
||||
_systems.Dispose();
|
||||
_world.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
public static class BacteriaModel
|
||||
{
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
[ext_resource type="Script" uid="uid://opbkqoaa7x2n" path="res://src/Equipment/Balancer.cs" id="7_2wkfx"]
|
||||
[ext_resource type="Script" uid="uid://yec84plemjv1" path="res://src/Equipment/SlicerTest.cs" id="8_2lg7i"]
|
||||
[ext_resource type="Script" uid="uid://culjdbwllmsyk" path="res://src/Equipment/StackerTest.cs" id="8_e2skk"]
|
||||
[ext_resource type="PackedScene" uid="uid://dr5gfg25sjr04" path="res://src/VoxelGrid/RtsController.tscn" id="11_21ota"]
|
||||
[ext_resource type="Script" uid="uid://0yvk53xc1dix" path="res://src/VoxelGrid/ItemPlacerTest.cs" id="12_6whqj"]
|
||||
[ext_resource type="Resource" uid="uid://cus0vfrtgh0uh" path="res://src/VoxelGrid/test_equipment.tres" id="13_njjff"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_2wkfx"]
|
||||
size = Vector3(1, 1, 2)
|
||||
@@ -21,12 +24,15 @@ _data = {
|
||||
}
|
||||
point_count = 2
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_6whqj"]
|
||||
size = Vector3(25, 1, 25)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_njjff"]
|
||||
size = Vector3(25, 1, 25)
|
||||
|
||||
[node name="VoxelGridNode" type="Node3D" unique_id=825696340]
|
||||
script = ExtResource("1_tsdpe")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=75458542]
|
||||
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, 1, 0, 0)
|
||||
|
||||
@@ -345,3 +351,19 @@ 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)
|
||||
|
||||
[node name="RTS" parent="." unique_id=1383983755 instance=ExtResource("11_21ota")]
|
||||
|
||||
[node name="Node" type="Node" parent="RTS" unique_id=1499015368]
|
||||
script = ExtResource("12_6whqj")
|
||||
PlaceAction = "place"
|
||||
EquipmentEntrys = [ExtResource("13_njjff")]
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1598166493]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
|
||||
mesh = SubResource("BoxMesh_6whqj")
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="MeshInstance3D" unique_id=919680718]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/StaticBody3D" unique_id=622210784]
|
||||
shape = SubResource("BoxShape3D_njjff")
|
||||
|
||||
@@ -77,79 +77,3 @@ public sealed class VoxelRegistry : IVoxelGridRegistry
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public enum Direction
|
||||
{
|
||||
Up, Down, Left, Right, Front, Back
|
||||
}
|
||||
public static class DirectionExtession
|
||||
{
|
||||
public static Vector3I ToVector(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Vector3I.Up,
|
||||
Direction.Down => Vector3I.Down,
|
||||
Direction.Left => Vector3I.Left,
|
||||
Direction.Right => Vector3I.Right,
|
||||
Direction.Front => Vector3I.Forward,
|
||||
Direction.Back => Vector3I.Back,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction Reverse(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Down,
|
||||
Direction.Down => Direction.Up,
|
||||
Direction.Left => Direction.Right,
|
||||
Direction.Right => Direction.Left,
|
||||
Direction.Front => Direction.Back,
|
||||
Direction.Back => Direction.Front,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction RotateClockWise(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Up,
|
||||
Direction.Down => Direction.Down,
|
||||
Direction.Left => Direction.Back,
|
||||
Direction.Right => Direction.Front,
|
||||
Direction.Front => Direction.Right,
|
||||
Direction.Back => Direction.Left,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
public static Direction RotateCounterClockWise(this Direction direction) => direction switch
|
||||
{
|
||||
Direction.Up => Direction.Up,
|
||||
Direction.Down => Direction.Down,
|
||||
Direction.Right => Direction.Front,
|
||||
Direction.Left => Direction.Back,
|
||||
Direction.Back => Direction.Right,
|
||||
Direction.Front => Direction.Left,
|
||||
_ => throw new NotSupportedException($"{nameof(direction)} does not support value {direction}")
|
||||
};
|
||||
}
|
||||
public interface IStorage<T> where T : class
|
||||
{
|
||||
StorageDefinition Definition { get; }
|
||||
IEnumerable<T> GetAllItems();
|
||||
void Remove(T item);
|
||||
bool TryInsert(T item);
|
||||
|
||||
record StorageDefinition(string Name, ItemType Type);
|
||||
}
|
||||
public record ItemType(string Name);
|
||||
public partial class ItemStoragePool : Node, IStorage<IBeltItem>
|
||||
{
|
||||
[Export] public int MaxAmount { get; set; } = 5;
|
||||
public IStorage<IBeltItem>.StorageDefinition Definition { get; set; } = default!;
|
||||
private readonly List<IBeltItem> _items = [];
|
||||
public IEnumerable<IBeltItem> GetAllItems() => _items;
|
||||
public bool TryInsert(IBeltItem item)
|
||||
{
|
||||
if (_items.Count >= MaxAmount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_items.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Remove(IBeltItem item) => _items.Remove(item);
|
||||
}
|
||||
|
||||
8
src/VoxelGrid/test_equipment.tres
Normal file
8
src/VoxelGrid/test_equipment.tres
Normal file
@@ -0,0 +1,8 @@
|
||||
[gd_resource type="Resource" format=3 uid="uid://cus0vfrtgh0uh"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://c4h7mwnfrdesg" path="res://src/Conveyors/ConveyorBeltStraight/ConveyorBeltStraight.tscn" id="1_ipx2f"]
|
||||
[ext_resource type="Script" uid="uid://x8adhd57sup8" path="res://src/Equipment/EquipmentEntry.cs" id="2_82d1t"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_82d1t")
|
||||
VisualScene = ExtResource("1_ipx2f")
|
||||
Reference in New Issue
Block a user