From 4880fea8e399456ba61cad0ea3a4d58d38206bf0 Mon Sep 17 00:00:00 2001 From: Ale32bit Date: Wed, 28 Jun 2023 16:22:38 +0200 Subject: [PATCH] So many small changes --- Capy64/Assets/Lua/bios.lua | 4 +- Capy64/Core/Audio.cs | 3 +- Capy64/Integrations/DiscordIntegration.cs | 10 ++- Capy64/Runtime/Extensions/Utils.cs | 15 +---- Capy64/Runtime/Libraries/AudioLib.cs | 8 ++- Capy64/Runtime/Libraries/EventLib.cs | 12 +++- Capy64/Runtime/Libraries/GPULib.cs | 77 +++++++++++++++++++++-- Capy64/Runtime/Libraries/HTTPLib.cs | 6 +- Capy64/Runtime/Libraries/TermLib.cs | 16 ++++- Capy64/Runtime/Libraries/TimerLib.cs | 2 +- Capy64/Runtime/LuaState.cs | 1 - Capy64/Runtime/ObjectManager.cs | 18 +++++- Capy64/Runtime/Objects/Socket.cs | 4 +- Capy64/Runtime/Objects/Task.cs | 72 ++++++++++++++++----- 14 files changed, 193 insertions(+), 55 deletions(-) diff --git a/Capy64/Assets/Lua/bios.lua b/Capy64/Assets/Lua/bios.lua index 0b9ad22..9a75b84 100644 --- a/Capy64/Assets/Lua/bios.lua +++ b/Capy64/Assets/Lua/bios.lua @@ -29,7 +29,9 @@ term.setForeground(fg) term.setBackground(bg) term.clear() -term.setSize(53, 20) +if term.isResizable() then + term.setSize(53, 20) +end local w, h = term.getSize() diff --git a/Capy64/Core/Audio.cs b/Capy64/Core/Audio.cs index a2c0202..1409a83 100644 --- a/Capy64/Core/Audio.cs +++ b/Capy64/Core/Audio.cs @@ -29,7 +29,7 @@ public class Audio : IDisposable Noise } - public const int SampleRate = 16000; + public const int SampleRate = 24000; public const int HQSampleRate = 48000; public const AudioChannels AudioChannel = AudioChannels.Mono; public const int ChannelsCount = 8; @@ -126,6 +126,7 @@ public class Audio : IDisposable public TimeSpan SubmitHQ(byte[] buffer) { + HQChannel.SubmitBuffer(buffer); return HQChannel.GetSampleDuration(buffer.Length); } diff --git a/Capy64/Integrations/DiscordIntegration.cs b/Capy64/Integrations/DiscordIntegration.cs index 810fb49..16db4bc 100644 --- a/Capy64/Integrations/DiscordIntegration.cs +++ b/Capy64/Integrations/DiscordIntegration.cs @@ -25,6 +25,7 @@ namespace Capy64.Integrations; public class DiscordIntegration : IComponent { public DiscordRpcClient Client { get; private set; } + public readonly bool Enabled; private readonly IConfiguration _configuration; public DiscordIntegration(IConfiguration configuration) @@ -32,6 +33,8 @@ public class DiscordIntegration : IComponent _configuration = configuration; var discordConfig = _configuration.GetSection("Integrations:Discord"); + Enabled = discordConfig.GetValue("Enable", false); + Client = new(discordConfig["ApplicationId"]) { Logger = new ConsoleLogger() { Level = LogLevel.Warning } @@ -41,15 +44,16 @@ public class DiscordIntegration : IComponent Capy64.Instance.Discord = this; - if (discordConfig.GetValue("Enable", false)) - { + if (Enabled) Client.Initialize(); - } } #nullable enable public void SetPresence(string details, string? state = null) { + if (!Enabled) + return; + Client.SetPresence(new RichPresence() { Details = details, diff --git a/Capy64/Runtime/Extensions/Utils.cs b/Capy64/Runtime/Extensions/Utils.cs index ca08b85..0374ae6 100644 --- a/Capy64/Runtime/Extensions/Utils.cs +++ b/Capy64/Runtime/Extensions/Utils.cs @@ -97,17 +97,4 @@ public static class Utils } return 1; } - - [Obsolete("This method does not work as intended and requires more research")] - public static void PushManagedObject(this Lua L, T obj) - { - var type = obj.GetType(); - var members = type.GetMembers().Where(m => m.MemberType == MemberTypes.Method); - L.CreateTable(0, members.Count()); - foreach (var m in members) - { - L.PushCFunction(L => (int)type.InvokeMember(m.Name, BindingFlags.InvokeMethod, null, obj, new object[] { L })); - L.SetField(-2, m.Name); - } - } -} +} \ No newline at end of file diff --git a/Capy64/Runtime/Libraries/AudioLib.cs b/Capy64/Runtime/Libraries/AudioLib.cs index 7168a62..2e1b317 100644 --- a/Capy64/Runtime/Libraries/AudioLib.cs +++ b/Capy64/Runtime/Libraries/AudioLib.cs @@ -103,12 +103,14 @@ public class AudioLib : IComponent { L.CheckType(1, LuaType.Table); var len = L.RawLen(1); - buffer = new byte[len]; + buffer = new byte[len * 2]; for (int i = 1; i <= len; i++) { L.GetInteger(1, i); - var value = L.CheckInteger(-1); - buffer[i - 1] = (byte)value; + // Convert 8bit PCM to 16bit PCM + var value = (short)(L.CheckNumber(-1) / sbyte.MaxValue * short.MaxValue); + buffer[2 * i - 2] = (byte)(value & 0xff); + buffer[2 * i - 1] = (byte)(value >> 8); L.Pop(1); } } diff --git a/Capy64/Runtime/Libraries/EventLib.cs b/Capy64/Runtime/Libraries/EventLib.cs index c3fbed1..ea05245 100644 --- a/Capy64/Runtime/Libraries/EventLib.cs +++ b/Capy64/Runtime/Libraries/EventLib.cs @@ -138,7 +138,11 @@ public class EventLib : IComponent { var L = Lua.FromIntPtr(state); - var task = TaskMeta.CheckTask(L, false); + L.CheckType(1, LuaType.Table); + + L.GetField(1, "task"); + + var task = TaskMeta.CheckTask(L, -1, false); L.CheckAny(2); L.ArgumentCheck(!L.IsNil(2), 2, "value cannot be nil"); @@ -164,7 +168,11 @@ public class EventLib : IComponent { var L = Lua.FromIntPtr(state); - var task = TaskMeta.CheckTask(L, false); + L.CheckType(1, LuaType.Table); + + L.GetField(1, "task"); + + var task = TaskMeta.CheckTask(L, -1, false); var error = L.CheckString(2); if (!task.UserTask) diff --git a/Capy64/Runtime/Libraries/GPULib.cs b/Capy64/Runtime/Libraries/GPULib.cs index 5d2db1d..504fde8 100644 --- a/Capy64/Runtime/Libraries/GPULib.cs +++ b/Capy64/Runtime/Libraries/GPULib.cs @@ -46,6 +46,11 @@ public class GPULib : IComponent function = L_SetSize, }, new() + { + name = "isResizable", + function = L_IsResizable, + }, + new() { name = "getPixel", function = L_GetPixel, @@ -116,6 +121,11 @@ public class GPULib : IComponent function = L_NewBuffer, }, new() + { + name = "bufferFrom", + function = L_BufferFrom, + }, + new() { name = "drawBuffer", function = L_DrawBuffer, @@ -168,8 +178,7 @@ public class GPULib : IComponent if (_game.EngineMode == EngineMode.Classic) { - L.PushBoolean(false); - return 1; + return L.Error("Screen is not resizable"); } var w = L.CheckInteger(1); @@ -185,6 +194,15 @@ public class GPULib : IComponent return 1; } + private static int L_IsResizable(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + L.PushBoolean(_game.EngineMode != EngineMode.Classic); + + return 1; + } + private static int L_GetPixel(IntPtr state) { var L = Lua.FromIntPtr(state); @@ -457,6 +475,57 @@ public class GPULib : IComponent return 1; } + private static int L_BufferFrom(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + L.CheckType(1, LuaType.Table); + var width = (int)L.CheckInteger(2); + var height = (int)L.CheckInteger(3); + + if (width <= 0) + { + return L.ArgumentError(2, "width must be a positive integer."); + } + + if (height <= 0) + { + return L.ArgumentError(3, "height must be a positive integer."); + } + + var buffer = new uint[width * height]; + + var tableSize = L.RawLen(1); + L.ArgumentCheck(tableSize == buffer.Length, 1, "table length does not match buffer size"); + + for (int i = 1; i <= tableSize; i++) + { + L.GetInteger(1, i); + var value = (uint)L.CheckInteger(-1); + L.Pop(1); + // ARGB to ABGR + value = + (value & 0xFF_00_00_00U) | + ((value & 0x00_FF_00_00U) >> 16) | // move R + (value & 0x00_00_FF_00U) | // move G + ((value & 0x00_00_00_FFU) << 16); // move B + + buffer[i - 1] = value; + } + + var gpuBuffer = new GPUBufferMeta.GPUBuffer + { + Buffer = buffer, + Width = width, + Height = height, + }; + + ObjectManager.PushObject(L, gpuBuffer); + L.SetMetaTable(GPUBufferMeta.ObjectType); + + return 1; + } + private static int L_DrawBuffer(IntPtr state) { var L = Lua.FromIntPtr(state); @@ -535,7 +604,7 @@ public class GPULib : IComponent } L.Pop(1); - if(L.GetField(-1, "scale") == LuaType.Table) + if (L.GetField(-1, "scale") == LuaType.Table) { float sx = 1; float sy = 1; @@ -552,7 +621,7 @@ public class GPULib : IComponent } L.Pop(1); - if(L.GetField(-1, "effects") == LuaType.Number) + if (L.GetField(-1, "effects") == LuaType.Number) { var flags = L.CheckInteger(-1); effects = (SpriteEffects)flags; diff --git a/Capy64/Runtime/Libraries/HTTPLib.cs b/Capy64/Runtime/Libraries/HTTPLib.cs index 5abb155..6179a7f 100644 --- a/Capy64/Runtime/Libraries/HTTPLib.cs +++ b/Capy64/Runtime/Libraries/HTTPLib.cs @@ -30,14 +30,14 @@ namespace Capy64.Runtime.Libraries; #nullable enable public class HTTPLib : IComponent { - private static IGame _game; - private static HttpClient _httpClient; + private static IGame _game = null!; + private static HttpClient _httpClient = null!; private static long _requestId; public static readonly HashSet WebSocketConnections = new(); public static readonly string UserAgent = $"Capy64/{Capy64.Version}"; - private static IConfiguration _configuration; + private static IConfiguration _configuration = null!; private readonly LuaRegister[] Library = new LuaRegister[] { new() diff --git a/Capy64/Runtime/Libraries/TermLib.cs b/Capy64/Runtime/Libraries/TermLib.cs index 5460471..f753bc4 100644 --- a/Capy64/Runtime/Libraries/TermLib.cs +++ b/Capy64/Runtime/Libraries/TermLib.cs @@ -99,6 +99,10 @@ internal class TermLib : IComponent name = "setSize", function = L_SetSize, }, + new() { + name = "isResizable", + function = L_IsResizable, + }, new() { name = "getForeground", @@ -397,8 +401,7 @@ internal class TermLib : IComponent if (_game.EngineMode == EngineMode.Classic) { - L.PushBoolean(false); - return 1; + return L.Error("Terminal is not resizable"); } var w = (int)L.CheckNumber(1); @@ -419,6 +422,15 @@ internal class TermLib : IComponent return 1; } + private static int L_IsResizable(IntPtr state) + { + var L = Lua.FromIntPtr(state); + + L.PushBoolean(_game.EngineMode != EngineMode.Classic); + + return 1; + } + private static int L_GetForegroundColor(IntPtr state) { var L = Lua.FromIntPtr(state); diff --git a/Capy64/Runtime/Libraries/TimerLib.cs b/Capy64/Runtime/Libraries/TimerLib.cs index bf36bb6..e15b2f9 100644 --- a/Capy64/Runtime/Libraries/TimerLib.cs +++ b/Capy64/Runtime/Libraries/TimerLib.cs @@ -26,7 +26,7 @@ class TimerLib : IComponent public class Timer { public int RemainingTicks = 0; - public TaskMeta.RuntimeTask? Task; + public TaskMeta.RuntimeTask Task = null!; } private readonly LuaRegister[] Library = new LuaRegister[] diff --git a/Capy64/Runtime/LuaState.cs b/Capy64/Runtime/LuaState.cs index c9750a8..f2845d0 100644 --- a/Capy64/Runtime/LuaState.cs +++ b/Capy64/Runtime/LuaState.cs @@ -60,7 +60,6 @@ public class LuaState : IDisposable if (yieldTimedOut) { L.Error("no yield timeout"); - Console.WriteLine("tick"); } } diff --git a/Capy64/Runtime/ObjectManager.cs b/Capy64/Runtime/ObjectManager.cs index 6c55530..5f4e011 100644 --- a/Capy64/Runtime/ObjectManager.cs +++ b/Capy64/Runtime/ObjectManager.cs @@ -32,16 +32,30 @@ public class ObjectManager : IComponent _game.EventEmitter.OnClose += OnClose; } - public static void PushObject(Lua L, T obj) + public static nint PushObject(Lua L, T obj) { if (obj == null) { L.PushNil(); - return; + return nint.Zero; } var p = L.NewUserData(1); _objects[p] = obj; + return p; + } + + public static T GetObject(nint address, bool freeGCHandle = false) + { + if (!_objects.ContainsKey(address)) + return default(T); + + var reference = (T)_objects[address]; + + if (freeGCHandle) + _objects.Remove(address, out _); + + return reference; } public static T ToObject(Lua L, int index, bool freeGCHandle = true) diff --git a/Capy64/Runtime/Objects/Socket.cs b/Capy64/Runtime/Objects/Socket.cs index 7069af2..63745e1 100644 --- a/Capy64/Runtime/Objects/Socket.cs +++ b/Capy64/Runtime/Objects/Socket.cs @@ -29,10 +29,10 @@ public class Socket : IDisposable public class SocketLib : IComponent { - private static readonly IGame _game; + private static IGame _game = null!; public SocketLib(IGame game) { - + _game = game; } private static readonly LuaRegister[] Methods = new LuaRegister[] { diff --git a/Capy64/Runtime/Objects/Task.cs b/Capy64/Runtime/Objects/Task.cs index e2143f1..fd8e9ed 100644 --- a/Capy64/Runtime/Objects/Task.cs +++ b/Capy64/Runtime/Objects/Task.cs @@ -43,6 +43,7 @@ public class TaskMeta : IComponent } public Guid Guid { get; set; } = Guid.NewGuid(); + public nint Pointer { get; set; } = nint.Zero; public string Name { get; set; } public TaskStatus Status { get; set; } = TaskStatus.Running; public string Error { get; private set; } @@ -79,7 +80,6 @@ public class TaskMeta : IComponent DataIndex = tasks.GetTop(); } - _game.LuaRuntime.QueueEvent("task_finish", LK => { LK.PushString(Guid.ToString()); @@ -203,26 +203,58 @@ public class TaskMeta : IComponent var task = new RuntimeTask(typeName); - ObjectManager.PushObject(L, task); + L.NewTable(); + task.Pointer = ObjectManager.PushObject(L, task); + L.SetMetaTable(ObjectType); + L.SetField(-2, "task"); + L.SetMetaTable(ObjectType); return task; } - public static RuntimeTask ToTask(Lua L, bool gc = false) + public static RuntimeTask ToTask(Lua L, int index = 1, bool gc = false) { - return ObjectManager.ToObject(L, 1, gc); + RuntimeTask task; + if (L.Type(index) != LuaType.Table) + { + if (L.TestUserData(index, ObjectType) == nint.Zero) + { + return null; + } + else + { + task = ObjectManager.ToObject(L, index, gc); + + } + } + else + { + L.GetField(index, "task"); + task = task = ObjectManager.ToObject(L, -1, gc); + } + return task; } - public static RuntimeTask CheckTask(Lua L, bool gc = false) + public static RuntimeTask CheckTask(Lua L, int index = 1, bool gc = false) { - var obj = ObjectManager.CheckObject(L, 1, ObjectType, gc); - if (obj is null) + RuntimeTask task; + if (L.Type(index) != LuaType.Table) + { + task = ObjectManager.CheckObject(L, index, ObjectType, gc); + } + else + { + L.GetField(index, "task"); + task = ObjectManager.CheckObject(L, -1, ObjectType, gc); + } + + if (task is null) { L.Error("attempt to use a closed task"); return null; } - return obj; + return task; } private static int FindSpot() @@ -268,7 +300,7 @@ public class TaskMeta : IComponent L.Warning("Native task awaiter should be avoided", false); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); if (task.Status == TaskStatus.Succeeded) { @@ -295,7 +327,9 @@ public class TaskMeta : IComponent private static int LK_Await(IntPtr state, int status, nint ctx) { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + + var task = CheckTask(L, 1, false); + var taskId = L.CheckString(3); if (task.Guid.ToString() != taskId) @@ -311,7 +345,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); L.PushString(task.Guid.ToString()); @@ -322,7 +356,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); L.PushString(task.Name); @@ -333,7 +367,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); L.PushString(task.Status.ToString().ToLower()); @@ -344,7 +378,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); if (task.Status == TaskStatus.Succeeded) { @@ -364,7 +398,7 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = CheckTask(L, false); + var task = CheckTask(L, 1, false); if (task.Status == TaskStatus.Failed) { @@ -382,7 +416,11 @@ public class TaskMeta : IComponent { var L = Lua.FromIntPtr(state); - var task = ToTask(L, true); + L.CheckType(1, LuaType.Table); + + L.GetField(1, "task"); + + var task = CheckTask(L, -1, true); if (task is null) return 0; @@ -400,7 +438,9 @@ public class TaskMeta : IComponent private static int LM_ToString(IntPtr state) { var L = Lua.FromIntPtr(state); + var task = ToTask(L); + L.PushString("Task<{0}>: {1} ({2})", task?.Name, task?.Guid, task?.Status); return 1;