Inventory management focused game written in Godot / C#
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.2 KiB

using Dictionary = Godot.Collections.Dictionary;
public partial class Workshop : Area3D
{
/// <summary> Returns whether this workshop is owned by the local player. </summary>
public bool IsLocal => this.IsAuthority();
/// <summary> Gets the peer ID of the player owning this workshop. </summary>
public int PeerId => GetMultiplayerAuthority();
/// <summary> Gets the player that owns this workshop. </summary>
public Player Player => Game.Players.ByPeerId(PeerId);
[Export] public Node Objects { get; private set; }
public void Clear()
{
// TODO: This is very ugly please send help.
var manager = this.GetNodeOrThrow<ItemManager>(nameof(ItemManager));
manager.TrackedItems.Clear();
foreach (var obj in Objects.GetChildren()) {
if (obj is Item) {
Objects.RemoveChild(obj);
obj.QueueFree();
}
if (obj.GetNodeOrNull(nameof(Grid)) is Grid g)
foreach (var child in g.GetChildren().OfType<Item>()) {
g.RemoveChild(child);
child.QueueFree();
}
// TODO: Do we need to do recursion here?
}
}
public void FromDictionary(Dictionary dict)
{
// TODO: File information shouldn't be handled by this.
var version = dict["version"].AsInt32();
if (version != 0) throw new Exception($"Unknown version '{version}'");
Clear();
var manager = this.GetNodeOrThrow<ItemManager>(nameof(ItemManager));
var objectsDict = dict["objects"].AsGodotDictionary<string, Dictionary>();
foreach (var (childName, childDict) in objectsDict)
FromDictionary(manager, Objects, childName, childDict);
}
static void FromDictionary(ItemManager manager, Node parent, string name, Dictionary dict)
{
Node node;
if (dict.ContainsKey("scene")) {
var sceneName = dict["scene"].AsString();
var scene = ResourceLoader.Load<PackedScene>(sceneName, "PackedScene");
var item = scene.Instantiate<Item>();
item.Name = name;
item.Transform = ArrayToTransform(dict["transform"].AsFloat32Array());
parent.AddChild(item);
manager.Add(item);
node = item;
} else {
node = parent.GetNodeOrThrow<Node>(name);
}
if (dict.ContainsKey("grid")) {
var grid = node.GetNodeOrThrow<Grid>(nameof(Grid));
var gridDict = dict["grid"].AsGodotDictionary<string, Dictionary>();
foreach (var (childName, childDict) in gridDict)
FromDictionary(manager, grid, childName, childDict);
}
}
public Dictionary ToDictionary()
{
var result = new Dictionary {
["version"] = 0,
};
var objects = new Dictionary();
foreach (var child in Objects.GetChildren())
objects[child.Name] = ToDictionary(child);
result["objects"] = objects;
return result;
}
// TODO: Rework the way object are loaded / saved.
// Since it will be likely that objects will have varying data
// associated with them, only save the scene / object ID and let
// the object itself handle loading and saving its data.
static Dictionary ToDictionary(Node node)
{
var result = new Dictionary();
if (node is Item item) {
result["scene"] = item.SceneFilePath;
result["transform"] = TransformToArray(item.Transform);
}
var grid = new Dictionary();
if (node.GetNodeOrNull(nameof(Grid)) is Grid g)
foreach (var child in g.GetChildren().OfType<Item>())
grid[child.Name] = ToDictionary(child);
if (grid.Count > 0)
result["grid"] = grid;
return result;
}
public void SaveToFile(string path)
{
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write)
?? throw new Exception($"Failed to open '{path}' for writing: {FileAccess.GetOpenError()}");
file.StoreString(Json.Stringify(ToDictionary()));
}
public void LoadFromFile(string path)
{
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read)
?? throw new Exception($"Failed to open '{path}' for reading: {FileAccess.GetOpenError()}");
var json = file.GetLine();
var dict = Json.ParseString(json).AsGodotDictionary();
FromDictionary(dict);
}
static float[] TransformToArray(Transform3D t)
=> [ t[0, 0], t[1, 0], t[2, 0],
t[0, 1], t[1, 1], t[2, 1],
t[0, 2], t[1, 2], t[2, 2],
t[3, 0], t[3, 1], t[3, 2] ];
static Transform3D ArrayToTransform(float[] a)
=> new(a[ 0], a[ 1], a[ 2],
a[ 3], a[ 4], a[ 5],
a[ 6], a[ 7], a[ 8],
a[ 9], a[10], a[11]);
}