From 7254ba638cd530e2c27c441a4af2692c397b6204 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Sat, 11 Feb 2023 22:59:57 +0100 Subject: [PATCH] Hacky object management --- Capy64/Runtime/Libraries/FileSystem.cs | 4 +- Capy64/Runtime/Libraries/GPU.cs | 7 +- Capy64/Runtime/Libraries/HTTP.cs | 3 +- Capy64/Runtime/ObjectManager.cs | 122 +++++++++++++++++++++++++ Capy64/Runtime/Objects/FileHandle.cs | 6 +- Capy64/Runtime/Objects/GPUBuffer.cs | 8 +- 6 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 Capy64/Runtime/ObjectManager.cs diff --git a/Capy64/Runtime/Libraries/FileSystem.cs b/Capy64/Runtime/Libraries/FileSystem.cs index cf6ae04..4fb3e1e 100644 --- a/Capy64/Runtime/Libraries/FileSystem.cs +++ b/Capy64/Runtime/Libraries/FileSystem.cs @@ -542,7 +542,9 @@ public class FileSystem : IPlugin } var fileStream = File.Open(path, fileMode, fileAccess, FileShare.ReadWrite); - L.PushObject(fileStream); + + ObjectManager.PushObject(L, fileStream); + //L.PushObject(fileStream); L.SetMetaTable(FileHandle.ObjectType); return 1; diff --git a/Capy64/Runtime/Libraries/GPU.cs b/Capy64/Runtime/Libraries/GPU.cs index 9806a86..c957ff6 100644 --- a/Capy64/Runtime/Libraries/GPU.cs +++ b/Capy64/Runtime/Libraries/GPU.cs @@ -397,7 +397,8 @@ public class GPU : IPlugin var buffer = new uint[_game.Width * _game.Height]; _game.Drawing.Canvas.GetData(buffer); - L.PushObject(buffer); + ObjectManager.PushObject(L, buffer); + //L.PushObject(buffer); L.SetMetaTable(GPUBuffer.ObjectType); return 1; @@ -423,7 +424,7 @@ public class GPU : IPlugin var buffer = new uint[width * height]; - L.PushObject(buffer); + ObjectManager.PushObject(L, buffer); L.SetMetaTable(GPUBuffer.ObjectType); return 1; @@ -484,7 +485,7 @@ public class GPU : IPlugin var data = new uint[texture.Width * texture.Height]; texture.GetData(data); - L.PushObject(data); + ObjectManager.PushObject(L, data); L.SetMetaTable(GPUBuffer.ObjectType); L.PushInteger(texture.Width); L.PushInteger(texture.Height); diff --git a/Capy64/Runtime/Libraries/HTTP.cs b/Capy64/Runtime/Libraries/HTTP.cs index b2fe64c..345fc00 100644 --- a/Capy64/Runtime/Libraries/HTTP.cs +++ b/Capy64/Runtime/Libraries/HTTP.cs @@ -210,7 +210,8 @@ public class HTTP : IPlugin LK.PushInteger(requestId); // arg 2, response data - L.PushObject(stream); + ObjectManager.PushObject(L, stream); + //L.PushObject(stream); L.SetMetaTable(FileHandle.ObjectType); /*if ((bool)options["binary"]) BinaryReadHandle.Push(LK, new(stream)); diff --git a/Capy64/Runtime/ObjectManager.cs b/Capy64/Runtime/ObjectManager.cs new file mode 100644 index 0000000..d00613a --- /dev/null +++ b/Capy64/Runtime/ObjectManager.cs @@ -0,0 +1,122 @@ +using Capy64.API; +using KeraLua; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.Runtime; + +public class ObjectManager : IPlugin +{ + private static ConcurrentDictionary _objects = new(); + private static IGame _game; + public ObjectManager(IGame game) + { + _game = game; + _game.EventEmitter.OnClose += OnClone; + } + + public static void PushObject(Lua L, T obj) + { + if (obj == null) + { + L.PushNil(); + return; + } + + L.NewTable(); + var rp = L.ToPointer(-1); + + //var handle = GCHandle.Alloc(obj); + //var op = GCHandle.ToIntPtr(handle); + + _objects[rp] = obj; + } + + public static T ToObject(Lua L, int index, bool freeGCHandle = true) + { + if (L.IsNil(index) || !L.IsTable(index)) + return default(T); + + var rp = L.ToPointer(index); + if (rp == IntPtr.Zero) + return default(T); + + if (!_objects.ContainsKey(rp)) + return default(T); + + var obj = _objects[rp]; + if(obj == null) + return default(T); + + if (freeGCHandle) + _objects.Remove(rp, out _); + + return (T)obj; + + /*var handle = GCHandle.FromIntPtr(Objects[rp]); + if (!handle.IsAllocated) + return default(T); + + var reference = (T)handle.Target; + + if (freeGCHandle) + handle.Free(); + + return reference;*/ + } + + public static T CheckObject(Lua L, int argument, string typeName, bool freeGCHandle = true) + { + if (L.IsNil(argument) || !L.IsTable(argument)) + return default(T); + + if(L.GetMetaField(argument, "__name") != LuaType.String) + return default(T); + + var mtName = L.ToString(-1); + L.Pop(1); + + if(mtName != typeName) + return default(T); + + var rp = L.ToPointer(argument); + if (rp == IntPtr.Zero) + return default(T); + + if (!_objects.ContainsKey(rp)) + return default(T); + + var obj = _objects[rp]; + if (obj == null) + return default(T); + + if (freeGCHandle) + _objects.Remove(rp, out _); + + return (T)obj; + + /* + + var handle = GCHandle.FromIntPtr(Objects[rp]); + if (!handle.IsAllocated) + return default(T); + + var reference = (T)handle.Target; + + if (freeGCHandle) + handle.Free(); + + return reference;*/ + } + + private void OnClone(object sender, EventArgs e) + { + _objects.Clear(); + } +} diff --git a/Capy64/Runtime/Objects/FileHandle.cs b/Capy64/Runtime/Objects/FileHandle.cs index 093ba5a..ffabbca 100644 --- a/Capy64/Runtime/Objects/FileHandle.cs +++ b/Capy64/Runtime/Objects/FileHandle.cs @@ -97,12 +97,14 @@ public class FileHandle : IPlugin private static Stream ToStream(Lua L, bool gc = false) { - return L.CheckObject(1, ObjectType, gc); + return ObjectManager.ToObject(L, 1, gc); + //return L.CheckObject(1, ObjectType, gc); } private static Stream CheckStream(Lua L, bool gc = false) { - var obj = L.CheckObject(1, ObjectType, gc); + var obj = ObjectManager.CheckObject(L, 1, ObjectType, gc); + //var obj = L.CheckObject(1, ObjectType, gc); if (obj is null) { L.Error("attempt to use a closed file"); diff --git a/Capy64/Runtime/Objects/GPUBuffer.cs b/Capy64/Runtime/Objects/GPUBuffer.cs index 5995577..ddbf6e7 100644 --- a/Capy64/Runtime/Objects/GPUBuffer.cs +++ b/Capy64/Runtime/Objects/GPUBuffer.cs @@ -58,18 +58,20 @@ public class GPUBuffer : IPlugin public static uint[] ToBuffer(Lua L, bool gc = false) { - return L.CheckObject(1, ObjectType, gc); + return ObjectManager.ToObject(L, 1, gc); + //return L.CheckObject(1, ObjectType, gc); } public static uint[] CheckBuffer(Lua L, bool gc = false) { - var obj = L.CheckObject(1, ObjectType, gc); + var obj = ObjectManager.CheckObject(L, 1, ObjectType, gc); + //var obj = L.CheckObject(1, ObjectType, gc); if (obj is null) { L.Error("attempt to use a closed buffer"); return null; } - return (uint[])obj; + return obj; } private static int LM_Index(IntPtr state)