190 lines
5.0 KiB
C#
190 lines
5.0 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Godot;
|
|
|
|
namespace AceFieldNewHorizon.Scripts.System;
|
|
|
|
public enum RotationDirection
|
|
{
|
|
Up, // 0 degrees
|
|
Right, // 90 degrees
|
|
Down, // 180 degrees
|
|
Left // 270 degrees
|
|
}
|
|
|
|
public record BuildingData(
|
|
PackedScene Scene,
|
|
Dictionary<string, int> Cost,
|
|
int Durability,
|
|
GridLayer Layer,
|
|
float BuildTime,
|
|
Vector2I Size = default,
|
|
RotationDirection[] AllowedRotations = null
|
|
)
|
|
{
|
|
public Vector2I Size { get; } = Size == default ? Vector2I.One : Size;
|
|
public RotationDirection[] AllowedRotations { get; } =
|
|
AllowedRotations ?? [RotationDirection.Up, RotationDirection.Right, RotationDirection.Down, RotationDirection.Left
|
|
];
|
|
|
|
public bool IsRotationAllowed(float degrees)
|
|
{
|
|
var direction = (RotationDirection)((Mathf.RoundToInt(degrees / 90f) % 4 + 4) % 4);
|
|
return AllowedRotations.Contains(direction);
|
|
}
|
|
|
|
public Vector2I GetRotatedSize(float degrees)
|
|
{
|
|
return (Mathf.RoundToInt(degrees / 90f) % 2) == 0 ? Size : new Vector2I(Size.Y, Size.X);
|
|
}
|
|
}
|
|
|
|
public partial class BuildingRegistry : Node
|
|
{
|
|
private Dictionary<string, BuildingData> _registry = new();
|
|
|
|
[Export] public string JsonPath { get; set; } = "res://Data/Buildings.json";
|
|
|
|
public override void _Ready()
|
|
{
|
|
LoadFromJson(JsonPath);
|
|
}
|
|
|
|
public void LoadFromJson(string path)
|
|
{
|
|
var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
|
if (file == null)
|
|
{
|
|
GD.PrintErr($"[BuildingRegistry] Failed to open {path}");
|
|
return;
|
|
}
|
|
|
|
var text = file.GetAsText();
|
|
file.Close();
|
|
|
|
var json = new Json();
|
|
var error = json.Parse(text);
|
|
if (error != Error.Ok)
|
|
{
|
|
GD.PrintErr($"[BuildingRegistry] Failed to parse JSON: {json.GetErrorMessage()}");
|
|
return;
|
|
}
|
|
|
|
var dict = (Godot.Collections.Dictionary)json.Data;
|
|
|
|
foreach (string key in dict.Keys)
|
|
{
|
|
// Each entry is a Dictionary with keys: "scene", "cost", "durability", "buildTime", "size", "allowedRotations"
|
|
var buildingDict = dict[key].AsGodotDictionary();
|
|
|
|
// Parse scene
|
|
var scenePath = buildingDict.ContainsKey("scene") ? buildingDict["scene"].AsString() : null;
|
|
if (string.IsNullOrEmpty(scenePath))
|
|
{
|
|
GD.PrintErr($"[BuildingRegistry] No scene path for '{key}'");
|
|
continue;
|
|
}
|
|
|
|
var scene = GD.Load<PackedScene>(scenePath);
|
|
if (scene == null)
|
|
{
|
|
GD.PrintErr($"[BuildingRegistry] Failed to load scene for '{key}' at {scenePath}");
|
|
continue;
|
|
}
|
|
|
|
// Parse cost
|
|
Dictionary<string, int> cost = new();
|
|
if (buildingDict.TryGetValue("cost", out var value))
|
|
{
|
|
var costDict = value.AsGodotDictionary();
|
|
foreach (string mat in costDict.Keys)
|
|
{
|
|
int val;
|
|
var obj = costDict[mat];
|
|
if (obj.VariantType == Variant.Type.PackedInt64Array)
|
|
val = (int)obj.AsInt64();
|
|
else if (obj.VariantType == Variant.Type.PackedInt32Array)
|
|
val = obj.AsInt32();
|
|
else
|
|
int.TryParse(obj.ToString(), out val);
|
|
cost[mat] = val;
|
|
}
|
|
}
|
|
|
|
// Parse durability
|
|
var durability = 0;
|
|
if (buildingDict.TryGetValue("durability", out var dObj))
|
|
{
|
|
if (dObj.VariantType == Variant.Type.PackedInt64Array)
|
|
durability = (int)dObj.AsInt64();
|
|
else if (dObj.VariantType == Variant.Type.PackedInt32Array)
|
|
durability = dObj.AsInt32();
|
|
else
|
|
int.TryParse(dObj.ToString(), out durability);
|
|
}
|
|
|
|
// Parse buildTime
|
|
var buildTime = 0f;
|
|
if (buildingDict.TryGetValue("buildTime", out var bObj))
|
|
{
|
|
switch (bObj.VariantType)
|
|
{
|
|
case Variant.Type.PackedFloat32Array or Variant.Type.PackedFloat64Array:
|
|
buildTime = (float)bObj.AsDouble();
|
|
break;
|
|
case Variant.Type.PackedInt64Array:
|
|
buildTime = bObj.AsInt64();
|
|
break;
|
|
case Variant.Type.PackedInt32Array:
|
|
buildTime = bObj.AsInt32();
|
|
break;
|
|
default:
|
|
float.TryParse(bObj.ToString(), out buildTime);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Parse size
|
|
var size = Vector2I.One;
|
|
if (buildingDict.TryGetValue("size", out var sObj))
|
|
{
|
|
var sizeArray = sObj.AsGodotArray();
|
|
if (sizeArray.Count == 2)
|
|
{
|
|
size = new Vector2I((int)sizeArray[0].AsInt64(), (int)sizeArray[1].AsInt64());
|
|
}
|
|
}
|
|
|
|
// Parse allowedRotations
|
|
RotationDirection[] allowedRotations = null;
|
|
if (buildingDict.TryGetValue("allowedRotations", out var arObj))
|
|
{
|
|
var arArray = arObj.AsGodotArray();
|
|
allowedRotations = new RotationDirection[arArray.Count];
|
|
for (var i = 0; i < arArray.Count; i++)
|
|
{
|
|
allowedRotations[i] = (RotationDirection)arArray[i].AsInt32();
|
|
}
|
|
}
|
|
|
|
var layer = GridLayer.Building;
|
|
if (buildingDict.TryGetValue("layer", out var lObj))
|
|
{
|
|
layer = (GridLayer)lObj.AsInt32();
|
|
}
|
|
|
|
var buildingData = new BuildingData(scene, cost, durability, layer, buildTime, size, allowedRotations);
|
|
_registry[key] = buildingData;
|
|
GD.Print($"[BuildingRegistry] Loaded building '{key}' from {scenePath}");
|
|
}
|
|
|
|
GD.Print($"[BuildingRegistry] Loaded {_registry.Count} buildings");
|
|
}
|
|
|
|
public BuildingData GetBuilding(string id)
|
|
{
|
|
_registry.TryGetValue(id, out var data);
|
|
return data;
|
|
}
|
|
}
|