From 498c4938550aa148d94706456be14c518cc405ea Mon Sep 17 00:00:00 2001 From: kalimag Date: Fri, 17 Apr 2026 17:01:15 +0200 Subject: [PATCH 01/10] Add `#nullable` to many Lua libs --- .../Api/Classes/SaveStateApi.cs | 2 + .../lua/CommonLibs/ClientLuaLibrary.cs | 22 ++--- .../lua/CommonLibs/EmulationLuaLibrary.cs | 8 +- .../lua/CommonLibs/GameInfoLuaLibrary.cs | 4 +- .../lua/CommonLibs/InputLuaLibrary.cs | 2 + .../lua/CommonLibs/JoypadLuaLibrary.cs | 2 + .../lua/CommonLibs/MemoryLuaLibrary.cs | 86 ++++++++++--------- .../CommonLibs/MemorySavestateLuaLibrary.cs | 2 + .../lua/CommonLibs/SQLiteLuaLibrary.cs | 2 + .../lua/CommonLibs/SaveStateLuaLibrary.cs | 2 + .../lua/CommonLibs/UserDataLuaLibrary.cs | 6 +- .../lua/LuaHelperLibs/DoomLuaLibrary.cs | 16 ++-- .../lua/LuaHelperLibs/EventsLuaLibrary.cs | 77 +++++++++-------- .../lua/LuaHelperLibs/MainMemoryLuaLibrary.cs | 6 +- .../lua/LuaHelperLibs/NDSLuaLibrary.cs | 2 + .../lua/LuaHelperLibs/StringLuaLibrary.cs | 48 ++++++----- 16 files changed, 160 insertions(+), 127 deletions(-) diff --git a/src/BizHawk.Client.Common/Api/Classes/SaveStateApi.cs b/src/BizHawk.Client.Common/Api/Classes/SaveStateApi.cs index 271f036ed20..4a06f50fa01 100644 --- a/src/BizHawk.Client.Common/Api/Classes/SaveStateApi.cs +++ b/src/BizHawk.Client.Common/Api/Classes/SaveStateApi.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.IO; namespace BizHawk.Client.Common diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs index 634d41cbdea..8d271e114ad 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using System.Diagnostics; using System.Drawing; @@ -17,14 +19,14 @@ namespace BizHawk.Client.Common [Description("A library for manipulating the EmuHawk client UI")] public sealed class ClientLuaLibrary : LuaLibraryBase, IRegisterFunctions { - public Lazy AllAPINames { get; set; } + public required Lazy AllAPINames { get; set; } - public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } + public required NLFAddCallback CreateAndRegisterNamedFunction { get; set; } [OptionalService] - private IVideoProvider VideoProvider { get; set; } + private IVideoProvider? VideoProvider { get; set; } - public IMainFormForApi MainForm { get; set; } + public required IMainFormForApi MainForm { get; set; } public ClientLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} @@ -247,7 +249,7 @@ public int ScreenHeight() [LuaMethodExample("client.screenshot( \"C:\\\" );")] [LuaMethod("screenshot", "if a parameter is passed it will function as the Screenshot As menu item of EmuHawk, else it will function as the Screenshot menu item")] - public void Screenshot(string path = null) + public void Screenshot(string? path = null) => APIs.EmuClient.Screenshot(path); [LuaMethodExample("client.screenshottoclipboard( );")] @@ -287,7 +289,7 @@ public void SetWindowSize(int size) "No more than `maxFrames` future frames will be emulated. Useful to avoid freezing " + "the client UI in case of accidentally never returning true from the callback. " + "Your timeout can be as low as 1 frame or as high as 32767 frames.")] - public string ShowFuture(LuaFunction luaf, long maxFrames, string name = null) + public string ShowFuture(LuaFunction luaf, long maxFrames, string? name = null) { if (maxFrames is < 1 or > EmuClientApi.SHOW_FUTURE_MAX_USER_TIMEOUT) { @@ -367,7 +369,7 @@ public LuaTable GetAvailableTools() [LuaMethodExample("local nlcliget = client.gettool( \"Tool name\" );")] [LuaMethod("gettool", "Returns an object that represents a tool of the given name (not case sensitive). If the tool is not open, it will be loaded if available. Use getavailabletools to get a list of names")] - public LuaTable GetTool(string name) + public LuaTable? GetTool(string name) { var selectedTool = APIs.Tool.GetTool(name); return selectedTool == null ? null : _th.ObjectToTable(selectedTool); @@ -375,7 +377,7 @@ public LuaTable GetTool(string name) [LuaMethodExample("local nlclicre = client.createinstance( \"objectname\" );")] [LuaMethod("createinstance", "returns a default instance of the given type of object if it exists (not case sensitive). Note: This will only work on objects which have a parameterless constructor. If no suitable type is found, or the type does not have a parameterless constructor, then nil is returned")] - public LuaTable CreateInstance(string name) + public LuaTable? CreateInstance(string name) { var instance = APIs.Tool.CreateInstance(name); return instance == null ? null : _th.ObjectToTable(instance); @@ -418,7 +420,7 @@ public void ExactSleep(int millis) [LuaMethodExample("client.addcheat(\"NNNPAK\");")] [LuaMethod("addcheat", "adds a cheat code, if supported")] - public void AddCheat(string code) + public void AddCheat(string? code) { if (string.IsNullOrWhiteSpace(code)) { @@ -438,7 +440,7 @@ public void AddCheat(string code) [LuaMethodExample("client.removecheat(\"NNNPAK\");")] [LuaMethod("removecheat", "removes a cheat, if it already exists")] - public void RemoveCheat(string code) + public void RemoveCheat(string? code) { if (string.IsNullOrWhiteSpace(code)) { diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/EmulationLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/EmulationLuaLibrary.cs index aa25df18682..072d2e9bb77 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/EmulationLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/EmulationLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using NLua; @@ -9,8 +11,8 @@ namespace BizHawk.Client.Common [Description("A library for interacting with the currently loaded emulator core")] public sealed class EmulationLuaLibrary : LuaLibraryBase { - public Action FrameAdvanceCallback { get; set; } - public Action YieldCallback { get; set; } + public required Action FrameAdvanceCallback { get; set; } + public required Action YieldCallback { get; set; } public EmulationLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} @@ -36,7 +38,7 @@ public int FrameCount() [LuaMethodExample("local obemudis = emu.disassemble( 0x8000 );")] [LuaMethod("disassemble", "Returns the disassembly object (disasm string and length int) for the given PC address. Uses System Bus domain if no domain name provided")] - public LuaTable Disassemble(uint pc, string name = "") + public LuaTable? Disassemble(uint pc, string name = "") { var (disasm, length) = APIs.Emulation.Disassemble(pc, name); if (length is 0) return null; diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/GameInfoLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/GameInfoLuaLibrary.cs index d9b38b8271d..b1807a098dd 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/GameInfoLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/GameInfoLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using BizHawk.Emulation.Common; using NLua; @@ -30,7 +32,7 @@ public bool InDatabase() [LuaMethodExample("local stgamget = gameinfo.getstatus( );")] [LuaMethod("getstatus", "returns the game database status of the currently loaded rom. Statuses are for example: GoodDump, BadDump, Hack, Unknown, NotInDatabase")] - public string GetStatus() + public string? GetStatus() => (APIs.Emulation.GetGameInfo()?.Status)?.ToString(); [LuaMethodExample("if ( gameinfo.isstatusbad( ) ) then\r\n\tconsole.log( \"returns the currently loaded rom's game database status is considered 'bad'\" );\r\nend;")] diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/InputLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/InputLuaLibrary.cs index de722ce6188..4778725a9ba 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/InputLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/InputLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using NLua; namespace BizHawk.Client.Common diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/JoypadLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/JoypadLuaLibrary.cs index eccc2680427..2ec3a982bca 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/JoypadLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/JoypadLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using NLua; diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/MemoryLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/MemoryLuaLibrary.cs index 3f09befa5d4..9deb6dccfe7 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/MemoryLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/MemoryLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using System.Linq; @@ -22,7 +24,7 @@ public LuaTable GetMemoryDomainList() [LuaMethodExample("local uimemget = memory.getmemorydomainsize( mainmemory.getname( ) );")] [LuaMethod("getmemorydomainsize", "Returns the number of bytes of the specified memory domain. If no domain is specified, or the specified domain doesn't exist, returns the current domain size")] - public uint GetMemoryDomainSize(string name = "") + public uint GetMemoryDomainSize(string? name = "") => APIs.Memory.GetMemoryDomainSize(name); [LuaMethodExample("local stmemget = memory.getcurrentmemorydomain( );")] @@ -42,34 +44,34 @@ public bool UseMemoryDomain(string domain) [LuaMethodExample("local stmemhas = memory.hash_region( 0x100, 50, mainmemory.getname( ) );")] [LuaMethod("hash_region", "Returns a hash as a string of a region of memory, starting from addr, through count bytes. If the domain is unspecified, it uses the current region.")] - public string HashRegion(long addr, int count, string domain = null) + public string HashRegion(long addr, int count, string? domain = null) => APIs.Memory.HashRegion(addr, count, domain); [LuaMethodExample("local uimemrea = memory.readbyte( 0x100, mainmemory.getname( ) );")] [LuaMethod("readbyte", "gets the value from the given address as an unsigned byte")] - public uint ReadByte(long addr, string domain = null) + public uint ReadByte(long addr, string? domain = null) => APIs.Memory.ReadByte(addr, domain); [LuaMethodExample("memory.writebyte( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("writebyte", "Writes the given value to the given address as an unsigned byte")] - public void WriteByte(long addr, uint value, string domain = null) + public void WriteByte(long addr, uint value, string? domain = null) => APIs.Memory.WriteByte(addr, value, domain); [LuaDeprecatedMethod] [LuaMethod("readbyterange", "Reads the address range that starts from address, and is length long. Returns a zero-indexed table containing the read values (an array of bytes.)")] [return: LuaZeroIndexed] - public LuaTable ReadByteRange(long addr, int length, string domain = null) + public LuaTable ReadByteRange(long addr, int length, string? domain = null) => _th.ListToTable(APIs.Memory.ReadByteRange(addr, length, domain), indexFrom: 0); [LuaMethodExample("local bytes = memory.read_bytes_as_array(0x100, 30, \"WRAM\");")] [LuaMethod("read_bytes_as_array", "Reads length bytes starting at addr into an array-like table (1-indexed).")] - public LuaTable ReadBytesAsArray(long addr, int length, string domain = null) + public LuaTable ReadBytesAsArray(long addr, int length, string? domain = null) => _th.ListToTable(APIs.Memory.ReadByteRange(addr, length, domain)); [LuaMethodExample("local bytes = memory.read_bytes_as_dict(0x100, 30, \"WRAM\");")] [LuaMethod("read_bytes_as_dict", "Reads length bytes starting at addr into a dict-like table (where the keys are the addresses, relative to the start of the domain).")] [return: LuaZeroIndexed] - public LuaTable ReadBytesAsDict(long addr, int length, string domain = null) + public LuaTable ReadBytesAsDict(long addr, int length, string? domain = null) => _th.MemoryBlockToTable(APIs.Memory.ReadByteRange(addr, length, domain), addr); #pragma warning disable MA0136 // [LuaMethodExample] normalizes line endings @@ -81,7 +83,7 @@ public LuaTable ReadBytesAsDict(long addr, int length, string domain = null) end """)] [LuaMethod("read_bytes_as_binary_string", "Reads {{length}} bytes starting at {{addr}} into a binary string. This string can be read with functions such as {{string.byte}} and {{string.unpack}}. This string can contain any bytes including null bytes, and is not suitable for display as text.")] - public byte[] ReadBytesAsString(long addr, int length, string domain = null) + public byte[] ReadBytesAsString(long addr, int length, string? domain = null) { var bytes = APIs.Memory.ReadByteRange(addr, length, domain); return bytes as byte[] ?? bytes.ToArray(); @@ -89,7 +91,7 @@ public byte[] ReadBytesAsString(long addr, int length, string domain = null) [LuaDeprecatedMethod] [LuaMethod("writebyterange", "Writes the given values to the given addresses as unsigned bytes")] - public void WriteByteRange([LuaZeroIndexed] LuaTable memoryblock, string domain = null) + public void WriteByteRange([LuaZeroIndexed] LuaTable memoryblock, string? domain = null) { #if true WriteBytesAsDict(memoryblock, domain); @@ -119,12 +121,12 @@ public void WriteByteRange([LuaZeroIndexed] LuaTable memoryblock, string domain [LuaMethodExample("memory.write_bytes_as_array(0x100, { 0xAB, 0x12, 0xCD, 0x34 });")] [LuaMethod("write_bytes_as_array", "Writes sequential bytes starting at addr.")] - public void WriteBytesAsArray(long addr, LuaTable bytes, string domain = null) + public void WriteBytesAsArray(long addr, LuaTable bytes, string? domain = null) => APIs.Memory.WriteByteRange(addr, _th.EnumerateValues(bytes).Select(l => (byte) l).ToList(), domain); [LuaMethodExample("memory.write_bytes_as_dict({ [0x100] = 0xAB, [0x104] = 0xCD, [0x106] = 0x12, [0x107] = 0x34, [0x108] = 0xEF });")] [LuaMethod("write_bytes_as_dict", "Writes bytes at arbitrary addresses (the keys of the given table are the addresses, relative to the start of the domain).")] - public void WriteBytesAsDict([LuaZeroIndexed] LuaTable addrMap, string domain = null) + public void WriteBytesAsDict([LuaZeroIndexed] LuaTable addrMap, string? domain = null) { foreach (var (addr, v) in addrMap) { @@ -138,13 +140,13 @@ public void WriteBytesAsDict([LuaZeroIndexed] LuaTable addrMap, string domain = memory.write_bytes_as_binary_string(0x10A, string.char(0xBE, 0xEF), "WRAM") """)] [LuaMethod("write_bytes_as_binary_string", "Writes bytes from a binary string to {{addr}}. The string can be created with functions such as {{string.pack}}, and can contain any bytes including null bytes. This is not a text encoding function.")] - public void WriteBytesAsString(long addr, byte[] bytes, string domain = null) + public void WriteBytesAsString(long addr, byte[] bytes, string? domain = null) => APIs.Memory.WriteByteRange(addr, bytes, domain); #pragma warning restore MA0136 [LuaMethodExample("local simemrea = memory.readfloat( 0x100, false, mainmemory.getname( ) );")] [LuaMethod("readfloat", "Reads the given address as a 32-bit float value from the main memory domain with th e given endian")] - public float ReadFloat(long addr, bool bigendian, string domain = null) + public float ReadFloat(long addr, bool bigendian, string? domain = null) { APIs.Memory.SetBigEndian(bigendian); return APIs.Memory.ReadFloat(addr, domain); @@ -152,7 +154,7 @@ public float ReadFloat(long addr, bool bigendian, string domain = null) [LuaMethodExample("memory.writefloat( 0x100, 10.0, false, mainmemory.getname( ) );")] [LuaMethod("writefloat", "Writes the given 32-bit float value to the given address and endian")] - public void WriteFloat(long addr, float value, bool bigendian, string domain = null) + public void WriteFloat(long addr, float value, bool bigendian, string? domain = null) { APIs.Memory.SetBigEndian(bigendian); APIs.Memory.WriteFloat(addr, value, domain); @@ -160,27 +162,27 @@ public void WriteFloat(long addr, float value, bool bigendian, string domain = n [LuaMethodExample("local inmemrea = memory.read_s8( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s8", "read signed byte")] - public int ReadS8(long addr, string domain = null) + public int ReadS8(long addr, string? domain = null) => APIs.Memory.ReadS8(addr, domain); [LuaMethodExample("memory.write_s8( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_s8", "write signed byte")] - public void WriteS8(long addr, uint value, string domain = null) + public void WriteS8(long addr, uint value, string? domain = null) => APIs.Memory.WriteS8(addr, unchecked((int) value), domain); [LuaMethodExample("local uimemrea = memory.read_u8( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u8", "read unsigned byte")] - public uint ReadU8(long addr, string domain = null) + public uint ReadU8(long addr, string? domain = null) => APIs.Memory.ReadU8(addr, domain); [LuaMethodExample("memory.write_u8( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u8", "write unsigned byte")] - public void WriteU8(long addr, uint value, string domain = null) + public void WriteU8(long addr, uint value, string? domain = null) => APIs.Memory.WriteU8(addr, value, domain); [LuaMethodExample("local inmemrea = memory.read_s16_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s16_le", "read signed 2 byte value, little endian")] - public int ReadS16Little(long addr, string domain = null) + public int ReadS16Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadS16(addr, domain); @@ -188,7 +190,7 @@ public int ReadS16Little(long addr, string domain = null) [LuaMethodExample("memory.write_s16_le( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s16_le", "write signed 2 byte value, little endian")] - public void WriteS16Little(long addr, int value, string domain = null) + public void WriteS16Little(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteS16(addr, value, domain); @@ -196,7 +198,7 @@ public void WriteS16Little(long addr, int value, string domain = null) [LuaMethodExample("local inmemrea = memory.read_s16_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s16_be", "read signed 2 byte value, big endian")] - public int ReadS16Big(long addr, string domain = null) + public int ReadS16Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadS16(addr, domain); @@ -204,7 +206,7 @@ public int ReadS16Big(long addr, string domain = null) [LuaMethodExample("memory.write_s16_be( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s16_be", "write signed 2 byte value, big endian")] - public void WriteS16Big(long addr, int value, string domain = null) + public void WriteS16Big(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteS16(addr, value, domain); @@ -212,7 +214,7 @@ public void WriteS16Big(long addr, int value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u16_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u16_le", "read unsigned 2 byte value, little endian")] - public uint ReadU16Little(long addr, string domain = null) + public uint ReadU16Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadU16(addr, domain); @@ -220,7 +222,7 @@ public uint ReadU16Little(long addr, string domain = null) [LuaMethodExample("memory.write_u16_le( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u16_le", "write unsigned 2 byte value, little endian")] - public void WriteU16Little(long addr, uint value, string domain = null) + public void WriteU16Little(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteU16(addr, value, domain); @@ -228,7 +230,7 @@ public void WriteU16Little(long addr, uint value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u16_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u16_be", "read unsigned 2 byte value, big endian")] - public uint ReadU16Big(long addr, string domain = null) + public uint ReadU16Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadU16(addr, domain); @@ -236,7 +238,7 @@ public uint ReadU16Big(long addr, string domain = null) [LuaMethodExample("memory.write_u16_be( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u16_be", "write unsigned 2 byte value, big endian")] - public void WriteU16Big(long addr, uint value, string domain = null) + public void WriteU16Big(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteU16(addr, value, domain); @@ -244,7 +246,7 @@ public void WriteU16Big(long addr, uint value, string domain = null) [LuaMethodExample("local inmemrea = memory.read_s24_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s24_le", "read signed 24 bit value, little endian")] - public int ReadS24Little(long addr, string domain = null) + public int ReadS24Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadS24(addr, domain); @@ -252,7 +254,7 @@ public int ReadS24Little(long addr, string domain = null) [LuaMethodExample("memory.write_s24_le( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s24_le", "write signed 24 bit value, little endian")] - public void WriteS24Little(long addr, int value, string domain = null) + public void WriteS24Little(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteS24(addr, value, domain); @@ -260,7 +262,7 @@ public void WriteS24Little(long addr, int value, string domain = null) [LuaMethodExample("local inmemrea = memory.read_s24_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s24_be", "read signed 24 bit value, big endian")] - public int ReadS24Big(long addr, string domain = null) + public int ReadS24Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadS24(addr, domain); @@ -268,7 +270,7 @@ public int ReadS24Big(long addr, string domain = null) [LuaMethodExample("memory.write_s24_be( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s24_be", "write signed 24 bit value, big endian")] - public void WriteS24Big(long addr, int value, string domain = null) + public void WriteS24Big(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteS24(addr, value, domain); @@ -276,7 +278,7 @@ public void WriteS24Big(long addr, int value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u24_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u24_le", "read unsigned 24 bit value, little endian")] - public uint ReadU24Little(long addr, string domain = null) + public uint ReadU24Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadU24(addr, domain); @@ -284,7 +286,7 @@ public uint ReadU24Little(long addr, string domain = null) [LuaMethodExample("memory.write_u24_le( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u24_le", "write unsigned 24 bit value, little endian")] - public void WriteU24Little(long addr, uint value, string domain = null) + public void WriteU24Little(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteU24(addr, value, domain); @@ -292,7 +294,7 @@ public void WriteU24Little(long addr, uint value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u24_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u24_be", "read unsigned 24 bit value, big endian")] - public uint ReadU24Big(long addr, string domain = null) + public uint ReadU24Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadU24(addr, domain); @@ -300,7 +302,7 @@ public uint ReadU24Big(long addr, string domain = null) [LuaMethodExample("memory.write_u24_be( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u24_be", "write unsigned 24 bit value, big endian")] - public void WriteU24Big(long addr, uint value, string domain = null) + public void WriteU24Big(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteU24(addr, value, domain); @@ -308,7 +310,7 @@ public void WriteU24Big(long addr, uint value, string domain = null) [LuaMethodExample("local inmemrea = memory.read_s32_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s32_le", "read signed 4 byte value, little endian")] - public int ReadS32Little(long addr, string domain = null) + public int ReadS32Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadS32(addr, domain); @@ -316,7 +318,7 @@ public int ReadS32Little(long addr, string domain = null) [LuaMethodExample("memory.write_s32_le( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s32_le", "write signed 4 byte value, little endian")] - public void WriteS32Little(long addr, int value, string domain = null) + public void WriteS32Little(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteS32(addr, value, domain); @@ -324,7 +326,7 @@ public void WriteS32Little(long addr, int value, string domain = null) [LuaMethodExample("local inmemrea = memory.read_s32_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_s32_be", "read signed 4 byte value, big endian")] - public int ReadS32Big(long addr, string domain = null) + public int ReadS32Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadS32(addr, domain); @@ -332,7 +334,7 @@ public int ReadS32Big(long addr, string domain = null) [LuaMethodExample("memory.write_s32_be( 0x100, -1000, mainmemory.getname( ) );")] [LuaMethod("write_s32_be", "write signed 4 byte value, big endian")] - public void WriteS32Big(long addr, int value, string domain = null) + public void WriteS32Big(long addr, int value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteS32(addr, value, domain); @@ -340,7 +342,7 @@ public void WriteS32Big(long addr, int value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u32_le( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u32_le", "read unsigned 4 byte value, little endian")] - public uint ReadU32Little(long addr, string domain = null) + public uint ReadU32Little(long addr, string? domain = null) { APIs.Memory.SetBigEndian(false); return APIs.Memory.ReadU32(addr, domain); @@ -348,7 +350,7 @@ public uint ReadU32Little(long addr, string domain = null) [LuaMethodExample("memory.write_u32_le( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u32_le", "write unsigned 4 byte value, little endian")] - public void WriteU32Little(long addr, uint value, string domain = null) + public void WriteU32Little(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(false); APIs.Memory.WriteU32(addr, value, domain); @@ -356,7 +358,7 @@ public void WriteU32Little(long addr, uint value, string domain = null) [LuaMethodExample("local uimemrea = memory.read_u32_be( 0x100, mainmemory.getname( ) );")] [LuaMethod("read_u32_be", "read unsigned 4 byte value, big endian")] - public uint ReadU32Big(long addr, string domain = null) + public uint ReadU32Big(long addr, string? domain = null) { APIs.Memory.SetBigEndian(); return APIs.Memory.ReadU32(addr, domain); @@ -364,7 +366,7 @@ public uint ReadU32Big(long addr, string domain = null) [LuaMethodExample("memory.write_u32_be( 0x100, 1000, mainmemory.getname( ) );")] [LuaMethod("write_u32_be", "write unsigned 4 byte value, big endian")] - public void WriteU32Big(long addr, uint value, string domain = null) + public void WriteU32Big(long addr, uint value, string? domain = null) { APIs.Memory.SetBigEndian(); APIs.Memory.WriteU32(addr, value, domain); diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/MemorySavestateLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/MemorySavestateLuaLibrary.cs index e1f938c282f..6428739fe62 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/MemorySavestateLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/MemorySavestateLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + // ReSharper disable UnusedMember.Global // ReSharper disable UnusedAutoPropertyAccessor.Local namespace BizHawk.Client.Common diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/SQLiteLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/SQLiteLuaLibrary.cs index 958ed59c539..86526d57953 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/SQLiteLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/SQLiteLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using System.ComponentModel; diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/SaveStateLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/SaveStateLuaLibrary.cs index 12f3e3649c1..48d9a7571fd 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/SaveStateLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/SaveStateLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace BizHawk.Client.Common { public sealed class SaveStateLuaLibrary : LuaLibraryBase diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/UserDataLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/UserDataLuaLibrary.cs index 9c0ff9af396..d901a12fa7b 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/UserDataLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/UserDataLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using NLua; @@ -15,12 +17,12 @@ public UserDataLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, [LuaMethodExample("userdata.set(\"Unique key\", \"Current key data\");")] [LuaMethod("set", "adds or updates the data with the given key with the given value")] - public void Set(string name, object value) + public void Set(string name, object? value) => APIs.UserData.Set(name, value); [LuaMethodExample("local obuseget = userdata.get( \"Unique key\" );")] [LuaMethod("get", "gets the data with the given key, if the key does not exist it will return nil")] - public object Get(string key) + public object? Get(string key) => APIs.UserData.Get(key); [LuaMethodExample("userdata.clear( );")] diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/DoomLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/DoomLuaLibrary.cs index 780b91b1038..24988d029a7 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/DoomLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/DoomLuaLibrary.cs @@ -1,4 +1,6 @@ -using System.ComponentModel; +#nullable enable + +using System.ComponentModel; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores; @@ -13,7 +15,7 @@ namespace BizHawk.Client.Common [Description("Functions specific to Doom games (functions may not run when a Doom game is not loaded)")] public sealed class DoomLuaLibrary : LuaLibraryBase, IRegisterFunctions { - public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } + public required NLFAddCallback CreateAndRegisterNamedFunction { get; set; } public DoomLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) { } @@ -22,7 +24,7 @@ public DoomLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Acti private const string ERR_MSG_UNSUPPORTED_CORE = $"`doom.*` functions can only be used with {CoreNames.DSDA}"; [RequiredService] - private IEmulator Emulator { get; set; } + private IEmulator Emulator { get; set; } = null!; /// loaded core is not DSDA-Doom #pragma warning disable MA0136 // multi-line string literals (passed to `[LuaMethodExample]`, which converts to host newlines) @@ -35,7 +37,7 @@ public DoomLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Acti [LuaMethod( name: "on_prandom", description: "Fires immediately after each P_Random() call by Doom. Your callback can have 1 parameter, which will be an integer identifying what kind of object or action made the RNG call.")] - public string OnPrandom(LuaFunction luaf, string name = null) + public string OnPrandom(LuaFunction luaf, string? name = null) { if (Emulator is not DSDA dsda) { @@ -62,7 +64,7 @@ public string OnPrandom(LuaFunction luaf, string name = null) [LuaMethod( name: "on_intercept", description: "Fires immediately after a new line or thing intercept is added by Doom. Your callback can have 3 parameters: integers identifying x and y position of the map block the intercept happened in, and whether the call is from `PIT_AddThingIntercepts()` (0) or `PIT_AddLineIntercepts()` (1).")] - public string OnIntercept(LuaFunction luaf, string name = null) + public string OnIntercept(LuaFunction luaf, string? name = null) { if (Emulator is not DSDA dsda) { @@ -89,7 +91,7 @@ public string OnIntercept(LuaFunction luaf, string name = null) [LuaMethod( name: "on_use", description: "Fires when P_UseSpecialLine() is called by a mobj (thing). Your callback can have 2 parameters, which will be pointers to activated line and to mobj that triggered it.")] - public string OnUse(LuaFunction luaf, string name = null) + public string OnUse(LuaFunction luaf, string? name = null) { if (Emulator is not DSDA dsda) { @@ -116,7 +118,7 @@ public string OnUse(LuaFunction luaf, string name = null) [LuaMethod( name: "on_cross", description: "Fires when P_CrossCompatibleSpecialLine() is called by a mobj (thing). Your callback can have 2 parameters, which will be pointers to activated line and to mobj that triggered it.")] - public string OnCross(LuaFunction luaf, string name = null) + public string OnCross(LuaFunction luaf, string? name = null) { if (Emulator is not DSDA dsda) { diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/EventsLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/EventsLuaLibrary.cs index 8fecdc5f337..2a73f32ee9b 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/EventsLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/EventsLuaLibrary.cs @@ -1,4 +1,7 @@ +#nullable enable + using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using NLua; using BizHawk.Emulation.Common; @@ -12,30 +15,30 @@ public sealed class EventsLuaLibrary : LuaLibraryBase, IRegisterFunctions { internal static readonly string EMPTY_UUID_STR = Guid.Empty.ToString("D"); - public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } + public required NLFAddCallback CreateAndRegisterNamedFunction { get; set; } - public NLFRemoveCallback RemoveNamedFunctionMatching { get; set; } + public required NLFRemoveCallback RemoveNamedFunctionMatching { get; set; } [OptionalService] - private IInputPollable InputPollableCore { get; set; } + private IInputPollable? InputPollableCore { get; set; } [OptionalService] - private IDebuggable DebuggableCore { get; set; } + private IDebuggable? DebuggableCore { get; set; } [RequiredService] - private IEmulator Emulator { get; set; } + private IEmulator Emulator { get; set; } = null!; [OptionalService] - private IMemoryDomains Domains { get; set; } + private IMemoryDomains? Domains { get; set; } public EventsLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} public override string Name => "event"; - private void AddMemCallbackOnCore(INamedLuaFunction nlf, MemoryCallbackType kind, string/*?*/ scope, uint? address) + private void AddMemCallbackOnCore(INamedLuaFunction nlf, MemoryCallbackType kind, string? scope, uint? address) { - var memCallbackImpl = DebuggableCore.MemoryCallbacks; + var memCallbackImpl = DebuggableCore!.MemoryCallbacks; MemoryCallbackDelegate memCallback = (addr, val, flags) => nlf.Call(addr, val, flags) is [ long n ] ? unchecked((uint) n) : null; @@ -62,24 +65,24 @@ private void LogScopeNotAvailable(string scope) [LuaMethod("can_use_callback_params", "Returns whether EmuHawk will pass arguments to callbacks. The current version passes arguments to \"memory\" callbacks (RAM/ROM/bus R/W), so this function will return true for that input. (It returns false for any other input.) This tells you whether it's necessary to enable workarounds/hacks because a script is running in a version without parameter support.")] [LuaMethodExample("local mem_callback = event.can_use_callback_params(\"memory\") and mem_callback or mem_callback_pre_29;")] - public bool CanUseCallbackParams(string subset = null) + public bool CanUseCallbackParams(string? subset = null) => subset is "memory"; [LuaMethodExample("local steveonf = event.onframeend(\r\n\tfunction()\r\n\t\tconsole.log( \"Calls the given lua function at the end of each frame, after all emulation and drawing has completed. Note: this is the default behavior of lua scripts\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("onframeend", "Calls the given lua function at the end of each frame, after all emulation and drawing has completed. Note: this is the default behavior of lua scripts")] - public string OnFrameEnd(LuaFunction luaf, string name = null) + public string OnFrameEnd(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_POSTFRAME, name: name) .GuidStr; [LuaMethodExample("local steveonf = event.onframestart(\r\n\tfunction()\r\n\t\tconsole.log( \"Calls the given lua function at the beginning of each frame before any emulation and drawing occurs\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("onframestart", "Calls the given lua function at the beginning of each frame before any emulation and drawing occurs")] - public string OnFrameStart(LuaFunction luaf, string name = null) + public string OnFrameStart(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_PREFRAME, name: name) .GuidStr; [LuaMethodExample("local steveoni = event.oninputpoll(\r\n\tfunction()\r\n\t\tconsole.log( \"Calls the given lua function after each time the emulator core polls for input\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("oninputpoll", "Calls the given lua function after each time the emulator core polls for input")] - public string OnInputPoll(LuaFunction luaf, string name = null) + public string OnInputPoll(LuaFunction luaf, string? name = null) { var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_INPUTPOLL, ApiGroup.PROHIBITED_MID_FRAME, name: name); //TODO should we bother registering the function if the service isn't supported? none of the other events work this way --yoshi @@ -112,7 +115,7 @@ private void LogNotImplemented() [LuaMethodExample("local steveonl = event.onloadstate(\r\n\tfunction()\r\n\tconsole.log( \"Fires after a state is loaded. Receives a lua function name, and registers it to the event immediately following a successful savestate event\" );\r\nend\", \"Frame name\" );")] [LuaMethod("onloadstate", "Fires after a state is loaded. Your callback can have 1 parameter, which will be the name of the loaded state.")] - public string OnLoadState(LuaFunction luaf, string name = null) + public string OnLoadState(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_LOADSTATE, name: name) .GuidStr; @@ -121,8 +124,8 @@ public string OnLoadState(LuaFunction luaf, string name = null) public string OnMemoryExecute( LuaFunction luaf, uint address, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { // Log("Deprecated function event.onmemoryexecute() used, replace the call with event.on_bus_exec()."); return OnBusExec(luaf, address, name: name, scope: scope); @@ -133,8 +136,8 @@ public string OnMemoryExecute( public string OnBusExec( LuaFunction luaf, uint address, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { try { @@ -167,8 +170,8 @@ public string OnBusExec( [LuaMethod("onmemoryexecuteany", "Fires immediately before every instruction executed (in the specified scope) by the core (CPU-intensive). Your callback can have 3 parameters {{(addr, val, flags)}}. {{val}} is the value to be executed (or {{0}} always, if this feature is only partially implemented).")] public string OnMemoryExecuteAny( LuaFunction luaf, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { // Log("Deprecated function event.onmemoryexecuteany(...) used, replace the call with event.on_bus_exec_any(...)."); return OnBusExecAny(luaf, name: name, scope: scope); @@ -178,8 +181,8 @@ public string OnMemoryExecuteAny( [LuaMethod("on_bus_exec_any", "Fires immediately before every instruction executed (in the specified scope) by the core (CPU-intensive). Your callback can have 3 parameters {{(addr, val, flags)}}. {{val}} is the value to be executed (or {{0}} always, if this feature is only partially implemented).")] public string OnBusExecAny( LuaFunction luaf, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { try { @@ -211,8 +214,8 @@ public string OnBusExecAny( public string OnMemoryRead( LuaFunction luaf, uint? address = null, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { // Log("Deprecated function event.onmemoryread(...) used, replace the call with event.on_bus_read(...)."); return OnBusRead(luaf, address, name: name, scope: scope); @@ -223,8 +226,8 @@ public string OnMemoryRead( public string OnBusRead( LuaFunction luaf, uint? address = null, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { try { @@ -256,8 +259,8 @@ public string OnBusRead( public string OnMemoryWrite( LuaFunction luaf, uint? address = null, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { // Log("Deprecated function event.onmemorywrite(...) used, replace the call with event.on_bus_write(...)."); return OnBusWrite(luaf, address, name: name, scope: scope); @@ -268,8 +271,8 @@ public string OnMemoryWrite( public string OnBusWrite( LuaFunction luaf, uint? address = null, - string name = null, - string scope = null) + string? name = null, + string? scope = null) { try { @@ -298,19 +301,19 @@ public string OnBusWrite( [LuaMethodExample("local steveons = event.onsavestate(\r\n\tfunction()\r\n\t\tconsole.log( \"Fires after a state is saved\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("onsavestate", "Fires after a state is saved. Your callback can have 1 parameter, which will be the name of the saved state.")] - public string OnSaveState(LuaFunction luaf, string name = null) + public string OnSaveState(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_SAVESTATE, name: name) .GuidStr; [LuaMethodExample("local steveone = event.onexit(\r\n\tfunction()\r\n\t\tconsole.log( \"Fires after the calling script has stopped\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("onexit", "Fires after the calling script has stopped")] - public string OnExit(LuaFunction luaf, string name = null) + public string OnExit(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_ENGINESTOP, name: name) .GuidStr; [LuaMethodExample("local closeGuid = event.onconsoleclose(\r\n\tfunction()\r\n\t\tconsole.log( \"Fires when the Lua Console closes\" );\r\n\tend\r\n\t, \"Frame name\" );")] [LuaMethod("onconsoleclose", "Fires when the Lua Console closes")] - public string OnConsoleClose(LuaFunction luaf, string name = null) + public string OnConsoleClose(LuaFunction luaf, string? name = null) => CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_CONSOLECLOSE, name: name) .GuidStr; @@ -337,7 +340,7 @@ public LuaTable AvailableScopes() : _th.CreateTable(); } - private string ProcessScope(string scope) + private string ProcessScope(string? scope) { if (string.IsNullOrWhiteSpace(scope)) { @@ -347,15 +350,15 @@ private string ProcessScope(string scope) } else { - scope = DebuggableCore.MemoryCallbacks.AvailableScopes[0]; + scope = DebuggableCore!.MemoryCallbacks.AvailableScopes[0]; } } - return scope; + return scope!; } - private bool HasScope(string scope) + private bool HasScope([NotNullWhen(false)] string? scope) => string.IsNullOrWhiteSpace(scope) - || DebuggableCore.MemoryCallbacks.AvailableScopes.AsSpan().Contains(scope); + || DebuggableCore!.MemoryCallbacks.AvailableScopes.AsSpan().Contains(scope); } } diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/MainMemoryLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/MainMemoryLuaLibrary.cs index d0fd2ad91fc..368a021f200 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/MainMemoryLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/MainMemoryLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using System.Linq; @@ -16,9 +18,9 @@ public MainMemoryLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer public override string Name => "mainmemory"; - private MemoryDomain _mainMemDomain; + private MemoryDomain? _mainMemDomain; - private string _mainMemName; + private string? _mainMemName; private MemoryDomain Domain => _mainMemDomain ??= ((MemoryApi) APIs.Memory).DomainList[MainMemName]!; diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/NDSLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/NDSLuaLibrary.cs index 33b7bb6668c..36053525fe1 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/NDSLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/NDSLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS; diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs index 373aa42d71e..9c051087753 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using System.Linq; using System.Text; @@ -48,7 +50,7 @@ public LuaTable Encode(string str, string encoding = "utf-8") + " A newline is NOT appended to the end, the result will end with a newline iff the input ended with one." + " The width parameter is in UTF-16 code units, and the string is folded at that width regardless of how wide the text appears or whether it already contains newlines or other whitespace." + " The separator parameter, if passed, will be used instead of a newline.")] - public string Fold(string str, int width, string/*?*/ separator = null) + public string Fold(string str, int width, string? separator = null) => str.Fold(width: width, separator: separator); [LuaMethodExample("local stbizhex = bizstring.hex( -12345 );")] @@ -104,81 +106,81 @@ public static string PadStart( [LuaMethodExample("local stbiztri = bizstring.trim( \"Some trim string\t \" );")] [LuaMethod("trim", "returns a string that trims whitespace on the left and right ends of the string")] - public static string Trim(string str) - => string.IsNullOrEmpty(str) ? null : str.Trim(); + public static string? Trim(string? str) + => string.IsNullOrEmpty(str) ? null : str!.Trim(); [LuaMethodExample("local stbizrep = bizstring.replace( \"Some string\", \"Some\", \"Replaced\" );")] [LuaMethod("replace", "Returns a string that replaces all occurrences of str2 in str1 with the value of replace")] - public static string Replace( - string str, + public static string? Replace( + string? str, string str2, - string replace) + string? replace) { return string.IsNullOrEmpty(str) ? null - : str.Replace(str2, replace); + : str!.Replace(str2, replace); } [LuaMethodExample("local stbiztou = bizstring.toupper( \"Some string\" );")] [LuaMethod("toupper", "Returns an uppercase version of the given string")] - public static string ToUpper(string str) + public static string? ToUpper(string? str) { return string.IsNullOrEmpty(str) ? null - : str.ToUpperInvariant(); + : str!.ToUpperInvariant(); } [LuaMethodExample("local stbiztol = bizstring.tolower( \"Some string\" );")] [LuaMethod("tolower", "Returns an lowercase version of the given string")] - public static string ToLower(string str) + public static string? ToLower(string? str) { return string.IsNullOrEmpty(str) ? null - : str.ToLowerInvariant(); + : str!.ToLowerInvariant(); } [LuaMethodExample("local stbizsub = bizstring.substring( \"Some string\", 6, 3 );")] [LuaMethod("substring", "Returns a string that represents a substring of str starting at position for the specified length")] - public static string SubString(string str, int position, int length) + public static string? SubString(string? str, int position, int length) { return string.IsNullOrEmpty(str) ? null - : str.Substring(position, length); + : str!.Substring(position, length); } [LuaMethodExample("local stbizrem = bizstring.remove( \"Some string\", 4, 5 );")] [LuaMethod("remove", "Returns a string that represents str with the given position and count removed")] - public static string Remove(string str, int position, int count) + public static string? Remove(string? str, int position, int count) { return string.IsNullOrEmpty(str) ? null - : str.Remove(position, count); + : str!.Remove(position, count); } [LuaMethodExample("if ( bizstring.contains( \"Some string\", \"Some\") ) then\r\n\tconsole.log( \"Returns whether or not str contains str2\" );\r\nend;")] [LuaMethod("contains", "Returns whether or not str contains str2")] - public static bool Contains(string str, string str2) - => !string.IsNullOrEmpty(str) && str.Contains(str2); // don't bother fixing encoding, will match (or not match) regardless + public static bool Contains(string? str, string str2) + => !string.IsNullOrEmpty(str) && str!.Contains(str2); // don't bother fixing encoding, will match (or not match) regardless [LuaMethodExample("if ( bizstring.startswith( \"Some string\", \"Some\") ) then\r\n\tconsole.log( \"Returns whether str starts with str2\" );\r\nend;")] [LuaMethod("startswith", "Returns whether str starts with str2")] - public static bool StartsWith(string str, string str2) - => !string.IsNullOrEmpty(str) && str.StartsWithOrdinal(str2); // don't bother fixing encoding, will match (or not match) regardless + public static bool StartsWith(string? str, string str2) + => !string.IsNullOrEmpty(str) && str!.StartsWithOrdinal(str2); // don't bother fixing encoding, will match (or not match) regardless [LuaMethodExample("if ( bizstring.endswith( \"Some string\", \"string\") ) then\r\n\tconsole.log( \"Returns whether str ends wth str2\" );\r\nend;")] [LuaMethod("endswith", "Returns whether str ends wth str2")] - public static bool EndsWith(string str, string str2) - => !string.IsNullOrEmpty(str) && str.EndsWithOrdinal(str2); // don't bother fixing encoding, will match (or not match) regardless + public static bool EndsWith(string? str, string str2) + => !string.IsNullOrEmpty(str) && str!.EndsWithOrdinal(str2); // don't bother fixing encoding, will match (or not match) regardless [LuaMethodExample("local nlbizspl = bizstring.split( \"Some, string\", \", \" );")] [LuaMethod("split", "Splits str into a Lua-style array using the given separator (consecutive separators in str will NOT create empty entries in the array). If the separator is not a string exactly one char long, ',' will be used.")] - public LuaTable Split(string str, string separator) + public LuaTable Split(string? str, string separator) { static char SingleOrElse(string s, char defaultValue) => s?.Length == 1 ? s[0] : defaultValue; return string.IsNullOrEmpty(str) ? _th.CreateTable() - : _th.ListToTable(str.Split(new[] { SingleOrElse(separator, ',') }, StringSplitOptions.RemoveEmptyEntries).ToList()); + : _th.ListToTable(str!.Split(new[] { SingleOrElse(separator, ',') }, StringSplitOptions.RemoveEmptyEntries).ToList()); } } } From fc3c25f6743bf125996de8ec2b018d53a4b4c3f4 Mon Sep 17 00:00:00 2001 From: kalimag Date: Sat, 18 Apr 2026 08:02:28 +0200 Subject: [PATCH 02/10] Enable `#nullable` for `NLuaTableHelper` --- src/BizHawk.Client.Common/lua/NLuaTableHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/NLuaTableHelper.cs b/src/BizHawk.Client.Common/lua/NLuaTableHelper.cs index 31ae8a4255e..b382378ea87 100644 --- a/src/BizHawk.Client.Common/lua/NLuaTableHelper.cs +++ b/src/BizHawk.Client.Common/lua/NLuaTableHelper.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Buffers; using System.Collections.Generic; using System.Drawing; @@ -105,9 +107,9 @@ public LuaTable ObjectToTable(object obj) public Color ParseColor(object o) => ParseColor(o, safe: false, _logCallback) ?? throw new ArgumentException("failed to parse Color", nameof(o)); - public Color? SafeParseColor(object o) => ParseColor(o, safe: true, _logCallback); + public Color? SafeParseColor(object? o) => ParseColor(o, safe: true, _logCallback); - private static Color? ParseColor(object o, bool safe, Action logCallback) + private static Color? ParseColor(object? o, bool safe, Action logCallback) { switch (o) { From 8d86619e683764e1ba24525bcafc12537b33ae0d Mon Sep 17 00:00:00 2001 From: kalimag Date: Sat, 18 Apr 2026 08:06:36 +0200 Subject: [PATCH 03/10] Enable `#nullable` on more Lua libs --- .../lua/CommonLibs/MovieLuaLibrary.cs | 8 +- .../tools/Lua/Libraries/FormsLuaLibrary.cs | 98 ++++++++++--------- .../tools/Lua/Libraries/GuiLuaLibrary.cs | 96 +++++++++--------- .../tools/Lua/Libraries/TAStudioLuaLibrary.cs | 32 +++--- 4 files changed, 121 insertions(+), 113 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/MovieLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/MovieLuaLibrary.cs index 5e127b02799..1b4522578c4 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/MovieLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/MovieLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using NLua; @@ -29,7 +31,7 @@ public string Filename() [LuaMethodExample("local nlmovget = movie.getinput( 500 );")] [LuaMethod("getinput", "Returns a table of buttons pressed on a given frame of the loaded movie")] - public LuaTable GetInput(int frame, int? controller = null) + public LuaTable? GetInput(int frame, int? controller = null) => APIs.Movie.GetInput(frame, controller) is IReadOnlyDictionary dict ? _th.DictToTable(dict) : null; @@ -71,7 +73,7 @@ public string Mode() [LuaMethodExample(@"movie.play_from_start(""C:\\moviename.ext"");")] [LuaMethod("play_from_start", "Resets the core to frame 0 with the currently loaded movie in playback mode. If a path to a movie is specified, attempts to load it, then continues with playback if it was successful. Returns true iff successful.")] - public bool PlayFromStart(string path = "") + public bool PlayFromStart(string? path = "") { if (_luaLibsImpl.ProhibitedApis.HasFlag(ApiGroup.BOOTING)) { @@ -86,7 +88,7 @@ public bool PlayFromStart(string path = "") [LuaMethodExample("movie.save( \"C:\\moviename.ext\" );")] [LuaMethod("save", "Saves the current movie to the disc. If the filename is provided (no extension or path needed), the movie is saved under the specified name to the current movie directory. The filename may contain a subdirectory, it will be created if it doesn't exist. Existing files won't get overwritten.")] - public void Save(string filename = "") + public void Save(string? filename = "") => APIs.Movie.Save(filename); [LuaMethodExample("movie.setreadonly( false );")] diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/FormsLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/FormsLuaLibrary.cs index 37cc39344b8..bf2fe163eda 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/FormsLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/FormsLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using System.ComponentModel; using System.Drawing; @@ -27,7 +29,7 @@ public sealed class FormsLuaLibrary : LuaLibraryBase, IDisposable public FormsLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} - public IDialogParent OwnerForm { get; set; } + public required IDialogParent OwnerForm { get; set; } public override string Name => "forms"; @@ -39,7 +41,7 @@ public void WindowClosed(IntPtr handle) if (i is not -1) _luaForms.RemoveAt(i); } - private LuaWinform GetForm(long formHandle) + private LuaWinform? GetForm(long formHandle) { var ptr = new IntPtr(formHandle); return _luaForms.Find(form => form.Handle == ptr); @@ -55,7 +57,7 @@ private static void SetSize(Control control, int width, int height) else control.Size = scaled; } - private static void SetText(Control control, string caption) + private static void SetText(Control control, string? caption) => control.Text = caption ?? string.Empty; public void Dispose() @@ -68,7 +70,7 @@ public void Dispose() public void AddClick(long handle, LuaFunction clickEvent) { var found = FindControlWithHandle(handle, out var form); - if (found is not null) form.ControlEvents.Add(new(found.Handle, clickEvent)); + if (found is not null) form!.ControlEvents.Add(new(found.Handle, clickEvent)); } [LuaMethodExample(""" @@ -136,7 +138,7 @@ public void ClearClicks(long handle) { var ptr = new IntPtr(handle); var found = FindControlWithHandle(ptr, out var form); - if (found is not null) form.ControlEvents.RemoveAll(x => x.Control == ptr); + if (found is not null) form!.ControlEvents.RemoveAll(x => x.Control == ptr); } [LuaMethodExample("if ( forms.destroy( 332 ) ) then\r\n\tconsole.log( \"Closes and removes a Lua created form with the specified handle. If a dialog was found and removed true is returned, else false\" );\r\nend;")] @@ -287,8 +289,8 @@ public long Label( public long NewForm( int? width = null, int? height = null, - string title = null, - LuaFunction onClose = null) + string? title = null, + LuaFunction? onClose = null) { if (OwnerForm is not IWin32Window ownerForm) throw new Exception("IDialogParent must implement IWin32Window"); @@ -313,9 +315,9 @@ public long NewForm( [LuaMethod( "openfile", "Creates a standard openfile dialog with optional parameters for the filename, directory, and filter. The return value is the directory that the user picked. If they chose to cancel, it will return an empty string")] public string OpenFile( - string fileName = null, - string initialDirectory = null, - string filter = null) + string? fileName = null, + string? initialDirectory = null, + string? filter = null) { if (initialDirectory is null && fileName is not null) initialDirectory = Path.GetDirectoryName(fileName); var result = OwnerForm.ShowFileOpenDialog( @@ -487,8 +489,8 @@ public void DrawBox( int y, int x2, int y2, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -524,8 +526,8 @@ public void DrawEllipse( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -725,7 +727,7 @@ public void DrawImageRegion( [LuaMethod( "drawLine", "Draws a line from the first coordinate pair to the 2nd. Color is optional (if not specified it will be drawn black)")] - public void DrawLine(long componentHandle, int x1, int y1, int x2, int y2, [LuaColorParam] object color = null) + public void DrawLine(long componentHandle, int x1, int y1, int x2, int y2, [LuaColorParam] object? color = null) { try { @@ -745,7 +747,7 @@ public void DrawLine(long componentHandle, int x1, int y1, int x2, int y2, [LuaC [LuaMethod( "drawAxis", "Draws an axis of the specified size at the coordinate pair.)")] - public void DrawAxis(long componentHandle, int x, int y, int size, [LuaColorParam] object color = null) + public void DrawAxis(long componentHandle, int x, int y, int size, [LuaColorParam] object? color = null) { try { @@ -774,7 +776,7 @@ public void DrawArc( int height, int startangle, int sweepangle, - [LuaColorParam] object line = null) + [LuaColorParam] object? line = null) { try { @@ -818,8 +820,8 @@ public void DrawPie( int height, int startangle, int sweepangle, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -857,7 +859,7 @@ public void DrawPie( [LuaMethod( "drawPixel", "Draws a single pixel at the given coordinates in the given color. Color is optional (if not specified it will be drawn black)")] - public void DrawPixel(long componentHandle, int x, int y, [LuaColorParam] object color = null) + public void DrawPixel(long componentHandle, int x, int y, [LuaColorParam] object? color = null) { try { @@ -888,8 +890,8 @@ public void DrawPolygon( LuaTable points, int? x = null, int? y = null, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -926,8 +928,8 @@ public void DrawRectangle( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -968,13 +970,13 @@ public void DrawString( int x, int y, string message, - [LuaColorParam] object forecolor = null, - [LuaColorParam] object backcolor = null, + [LuaColorParam] object? forecolor = null, + [LuaColorParam] object? backcolor = null, int? fontsize = null, - string fontfamily = null, - string fontstyle = null, - string horizalign = null, - string vertalign = null) + string? fontfamily = null, + string? fontstyle = null, + string? horizalign = null, + string? vertalign = null) => DrawText( componentHandle: componentHandle, x: x, @@ -997,13 +999,13 @@ public void DrawText( int x, int y, string message, - [LuaColorParam] object forecolor = null, - [LuaColorParam] object backcolor = null, + [LuaColorParam] object? forecolor = null, + [LuaColorParam] object? backcolor = null, int? fontsize = null, - string fontfamily = null, - string fontstyle = null, - string horizalign = null, - string vertalign = null) + string? fontfamily = null, + string? fontstyle = null, + string? horizalign = null, + string? vertalign = null) { try { @@ -1039,7 +1041,7 @@ public void DrawText( } } - private Control/*?*/ FindControlWithHandle(IntPtr handle) + private Control? FindControlWithHandle(IntPtr handle) { foreach (var form in _luaForms) foreach (Control control in form.Controls) { @@ -1048,7 +1050,7 @@ public void DrawText( return null; } - private Control/*?*/ FindControlWithHandle(IntPtr handle, out LuaWinform parentForm) + private Control? FindControlWithHandle(IntPtr handle, out LuaWinform? parentForm) { foreach (var form in _luaForms) foreach (Control control in form.Controls) { @@ -1060,13 +1062,13 @@ public void DrawText( return null; } - private Control/*?*/ FindControlWithHandle(long handle) + private Control? FindControlWithHandle(long handle) => FindControlWithHandle(new IntPtr(handle)); - private Control/*?*/ FindControlWithHandle(long handle, out LuaWinform parentForm) + private Control? FindControlWithHandle(long handle, out LuaWinform? parentForm) => FindControlWithHandle(new IntPtr(handle), out parentForm); - private Control/*?*/ FindFormOrControlWithHandle(IntPtr handle) + private Control? FindFormOrControlWithHandle(IntPtr handle) { foreach (var form in _luaForms) { @@ -1076,7 +1078,7 @@ public void DrawText( return null; } - private Control/*?*/ FindFormOrControlWithHandle(long handle) + private Control? FindFormOrControlWithHandle(long handle) => FindFormOrControlWithHandle(new IntPtr(handle)); // It'd be great if these were simplified into 1 function, but I cannot figure out how to return a LuaTable from this class @@ -1187,7 +1189,7 @@ public void SetLocation(long handle, int x, int y) /// [LuaMethodExample("forms.setproperty( 332, \"Property\", \"Property value\" );")] [LuaMethod("setproperty", "Attempts to set the given property of the widget with the given value. Note: not all properties will be able to be represented for the control to accept")] - public void SetProperty(long handle, string property, object value) + public void SetProperty(long handle, string property, object? value) { var c = FindFormOrControlWithHandle(handle); if (c is null) return; @@ -1195,9 +1197,9 @@ public void SetProperty(long handle, string property, object value) var pi = c.GetType().GetProperty(property) ?? throw new Exception($"no property with the identifier {property}"); var pt = pi.PropertyType; var o = pt.IsEnum - ? Enum.Parse(pt, value.ToString(), true) + ? Enum.Parse(pt, value!.ToString(), true) : pt == typeof(Color) - ? _th.ParseColor(value) + ? _th.ParseColor(value!) : Convert.ChangeType(value, pt); pi.SetValue(c, o, null); } @@ -1249,15 +1251,15 @@ public void Settext(long handle, string caption) + " Passing \"Vertical\", \"Horizontal\", \"Both\", or \"None\" for the scrollbars parameter will set whether the vertical scrollbar is visible for a multiline textbox, and also whether lines should wrap or remain in-line with a scrollbar.")] // technically case-insensitive but let's stick to fixed values public long Textbox( long formHandle, - string caption = null, + string? caption = null, int? width = null, int? height = null, - string boxtype = null, + string? boxtype = null, int? x = null, int? y = null, bool multiline = false, bool fixedWidth = false, - string scrollbars = null) + string? scrollbars = null) { var form = GetForm(formHandle); if (form == null) diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs index 4c06f27caa2..7133fe90acb 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Drawing; using System.Linq; @@ -15,7 +17,7 @@ public GuiLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Actio public override string Name => "gui"; - private DisplaySurfaceID UseOrFallback(string surfaceName) + private DisplaySurfaceID UseOrFallback(string? surfaceName) => DisplaySurfaceIDParser.Parse(surfaceName) ?? _rememberedSurfaceID; #pragma warning disable CS0612 @@ -39,7 +41,7 @@ public void AddMessage(string message) [LuaMethodExample("gui.clearGraphics( );")] [LuaMethod("clearGraphics", "clears all lua drawn graphics from the screen")] - public void ClearGraphics(string surfaceName = null) + public void ClearGraphics(string? surfaceName = null) => APIs.Gui.ClearGraphics(surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.cleartext( );")] @@ -72,7 +74,7 @@ public void SetDefaultPixelFont(string fontfamily) public void DrawBezier( LuaTable points, [LuaColorParam] object color, - string surfaceName = null) + string? surfaceName = null) { try { @@ -103,9 +105,9 @@ public void DrawBox( int y, int x2, int y2, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null, - string surfaceName = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null, + string? surfaceName = null) => APIs.Gui.DrawBox(x, y, x2, y2, _th.SafeParseColor(line), _th.SafeParseColor(background), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawEllipse( 16, 32, 77, 99, 0x007F00FF, 0x7F7F7FFF );")] @@ -115,9 +117,9 @@ public void DrawEllipse( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null, - string surfaceName = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null, + string? surfaceName = null) => APIs.Gui.DrawEllipse(x, y, width, height, _th.SafeParseColor(line), _th.SafeParseColor(background), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample(""" @@ -134,7 +136,7 @@ public void DrawIcon( int y, int? width = null, int? height = null, - string surfaceName = null) + string? surfaceName = null) => APIs.Gui.DrawIcon(path, x, y, width, height, surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample(""" @@ -153,7 +155,7 @@ public void DrawImage( int? width = null, int? height = null, bool cache = true, - string surfaceName = null) + string? surfaceName = null) => APIs.Gui.DrawImage(path, x, y, width, height, cache, surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.clearImageCache( );")] @@ -179,7 +181,7 @@ public void DrawImageRegion( int dest_y, int? dest_width = null, int? dest_height = null, - string surfaceName = null) + string? surfaceName = null) => APIs.Gui.DrawImageRegion(path, source_x, source_y, source_width, source_height, dest_x, dest_y, dest_width, dest_height, surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawLine( 161, 321, 162, 322, 0xFFFFFFFF );")] @@ -189,8 +191,8 @@ public void DrawLine( int y1, int x2, int y2, - [LuaColorParam] object color = null, - string surfaceName = null) + [LuaColorParam] object? color = null, + string? surfaceName = null) => APIs.Gui.DrawLine(x1, y1, x2, y2, _th.SafeParseColor(color), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawAxis( 16, 32, 15, 0xFFFFFFFF );")] @@ -199,8 +201,8 @@ public void DrawAxis( int x, int y, int size, - [LuaColorParam] object color = null, - string surfaceName = null) + [LuaColorParam] object? color = null, + string? surfaceName = null) => APIs.Gui.DrawAxis(x, y, size, _th.SafeParseColor(color), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawPie( 16, 32, 77, 99, 180, 90, 0x007F00FF, 0x7F7F7FFF );")] @@ -212,9 +214,9 @@ public void DrawPie( int height, int startangle, int sweepangle, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null, - string surfaceName = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null, + string? surfaceName = null) => APIs.Gui.DrawPie(x, y, width, height, startangle, sweepangle, _th.SafeParseColor(line), _th.SafeParseColor(background), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawPixel( 16, 32, 0xFFFFFFFF );")] @@ -222,8 +224,8 @@ public void DrawPie( public void DrawPixel( int x, int y, - [LuaColorParam] object color = null, - string surfaceName = null) + [LuaColorParam] object? color = null, + string? surfaceName = null) => APIs.Gui.DrawPixel(x, y, _th.SafeParseColor(color), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample(""" @@ -240,9 +242,9 @@ public void DrawPolygon( LuaTable points, int? offsetX = null, int? offsetY = null, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null, - string surfaceName = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null, + string? surfaceName = null) { var pointsList = _th.EnumerateValues(points) .Select(table => _th.EnumerateValues(table).ToList()).ToList(); @@ -270,9 +272,9 @@ public void DrawRectangle( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null, - string surfaceName = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null, + string? surfaceName = null) => APIs.Gui.DrawRectangle(x, y, width, height, _th.SafeParseColor(line), _th.SafeParseColor(background), surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.drawString( 16, 32, \"Some message\", 0x7F0000FF, 0x00007FFF, 8, \"Arial Narrow\", \"bold\", \"center\", \"middle\" );")] @@ -281,14 +283,14 @@ public void DrawString( int x, int y, string message, - [LuaColorParam] object forecolor = null, - [LuaColorParam] object backcolor = null, + [LuaColorParam] object? forecolor = null, + [LuaColorParam] object? backcolor = null, int? fontsize = null, - string fontfamily = null, - string fontstyle = null, - string horizalign = null, - string vertalign = null, - string surfaceName = null) + string? fontfamily = null, + string? fontstyle = null, + string? horizalign = null, + string? vertalign = null, + string? surfaceName = null) => APIs.Gui.DrawString( x: x, y: y, @@ -309,14 +311,14 @@ public void DrawText( int x, int y, string message, - [LuaColorParam] object forecolor = null, - [LuaColorParam] object backcolor = null, + [LuaColorParam] object? forecolor = null, + [LuaColorParam] object? backcolor = null, int? fontsize = null, - string fontfamily = null, - string fontstyle = null, - string horizalign = null, - string vertalign = null, - string surfaceName = null) + string? fontfamily = null, + string? fontstyle = null, + string? horizalign = null, + string? vertalign = null, + string? surfaceName = null) => DrawString( x: x, y: y, @@ -336,10 +338,10 @@ public void PixelText( int x, int y, string message, - [LuaColorParam] object forecolor = null, - [LuaColorParam] object backcolor = null, - string fontfamily = null, - string surfaceName = null) + [LuaColorParam] object? forecolor = null, + [LuaColorParam] object? backcolor = null, + string? fontfamily = null, + string? surfaceName = null) => APIs.Gui.PixelText(x, y, message, _th.SafeParseColor(forecolor), _th.SafeParseColor(backcolor) ?? APIs.Gui.GetDefaultTextBackground(), fontfamily, surfaceID: UseOrFallback(surfaceName)); [LuaMethodExample("gui.text( 16, 32, \"Some message\", 0x7F0000FF, \"bottomleft\" );")] @@ -348,8 +350,8 @@ public void Text( int x, int y, string message, - [LuaColorParam] object forecolor = null, - string anchor = null) + [LuaColorParam] object? forecolor = null, + string? anchor = null) => APIs.Gui.Text(x, y, message, _th.SafeParseColor(forecolor), anchor); [LuaMethodExample(""" diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs index 6c7406e0428..13c7881b814 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +#nullable enable + +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; @@ -26,9 +28,9 @@ private const string DESC_LINE_BRANCH_CHANGE_CB private static readonly IDictionary _iconCache = new Dictionary(); - public ToolManager Tools { get; set; } + public required ToolManager Tools { get; set; } - public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } + public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } = null!; public TAStudioLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} @@ -531,7 +533,7 @@ public void LoadBranch(int index) description: "Returns the label of the marker on the given frame. This may be an empty string." + " If that frame doesn't have a marker (or TAStudio isn't running), returns nil." + " If branchID is specified, searches the markers in that branch instead.")] - public string/*?*/ GetMarker(int frame, string/*?*/ branchID = null) + public string? GetMarker(int frame, string? branchID = null) { if (Engaged()) { @@ -546,7 +548,7 @@ public void LoadBranch(int index) } /// assumes a TAStudio project is loaded - private TasMovieMarkerList/*?*/ MarkerListForBranch(string/*?*/ branchID) + private TasMovieMarkerList? MarkerListForBranch(string? branchID) => Guid.TryParseExact(branchID, format: "D", out var parsed) ? Tastudio.CurrentTasMovie.Branches.FirstOrDefault(branch => branch.Uuid == parsed)?.Markers : branchID is null ? Tastudio.CurrentTasMovie.Markers : null; // not a typo; null `branchID` indicates main log @@ -559,7 +561,7 @@ public void LoadBranch(int index) description: "Returns the frame number of the marker closest to the given frame (including that frame, but not after it)." + " This may be the power-on marker at 0. Returns nil if the arguments are invalid or TAStudio isn't active." + " If branchID is specified, searches the markers in that branch instead.")] - public int? FindMarkerOnOrBefore(int frame, string/*?*/ branchID = null) + public int? FindMarkerOnOrBefore(int frame, string? branchID = null) => Engaged() && MarkerListForBranch(branchID) is TasMovieMarkerList markers ? markers.PreviousOrCurrent(frame)?.Frame : null; @@ -571,7 +573,7 @@ public void LoadBranch(int index) name: "get_frames_with_markers", description: "Returns a list of all the frames which have markers on them." + " If branchID is specified, instead returns the frames which have markers in that branch.")] - public LuaTable GetFramesWithMarkers(string/*?*/ branchID = null) + public LuaTable GetFramesWithMarkers(string? branchID = null) => Engaged() && MarkerListForBranch(branchID) is TasMovieMarkerList markers ? _th.EnumerateToLuaTable(markers.Select(static m => m.Frame)) : _th.CreateTable(); @@ -592,7 +594,7 @@ public void RemoveMarker(int frame) [LuaMethodExample("tastudio.setmarker( 500, \"Some message\" );")] [LuaMethod("setmarker", "Adds or sets a marker at the given frame, with an optional message")] - public void SetMarker(int frame, string message = null) + public void SetMarker(int frame, string? message = null) { if (Engaged()) { @@ -611,7 +613,7 @@ public void SetMarker(int frame, string message = null) [LuaMethodExample("tastudio.onqueryitembg( function( currentindex, itemname )\r\n\tconsole.log( \"called during the background draw event of the tastudio listview. luaf must be a function that takes 2 params: index, column. The first is the integer row index of the listview, and the 2nd is the string column name. luaf should return a value that can be parsed into a .NET Color object (string color name, or integer value)\" );\r\nend );")] [LuaMethod("onqueryitembg", "called during the background draw event of the tastudio listview. luaf must be a function that takes 2 params: index, column. The first is the integer row index of the listview, and the 2nd is the string column name. luaf should return a value that can be parsed into a .NET Color object (string color name, or integer value)")] - public string OnQueryItemBg(LuaFunction luaf, string name = null) + public string OnQueryItemBg(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -628,7 +630,7 @@ public string OnQueryItemBg(LuaFunction luaf, string name = null) [LuaMethodExample("tastudio.onqueryitemtext( function( currentindex, itemname )\r\n\tconsole.log( \"called during the text draw event of the tastudio listview. luaf must be a function that takes 2 params: index, column. The first is the integer row index of the listview, and the 2nd is the string column name. luaf should return a value that can be parsed into a .NET Color object (string color name, or integer value)\" );\r\nend );")] [LuaMethod("onqueryitemtext", "Called during the text draw event of the tastudio listview. {{luaf}} must be a function that takes 2 params: {{(index, column)}}. The first is the integer row index of the listview, and the 2nd is the string column name. The callback should return a string to be displayed.")] - public string OnQueryItemText(LuaFunction luaf, string name = null) + public string OnQueryItemText(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -645,7 +647,7 @@ public string OnQueryItemText(LuaFunction luaf, string name = null) [LuaMethodExample("tastudio.onqueryitemicon( function( currentindex, itemname )\r\n\tconsole.log( \"called during the icon draw event of the tastudio listview. luaf must be a function that takes 2 params: index, column. The first is the integer row index of the listview, and the 2nd is the string column name. luaf should return a value that can be parsed into a .NET Color object (string color name, or integer value)\" );\r\nend );")] [LuaMethod("onqueryitemicon", "Called during the icon draw event of the tastudio listview. {{luaf}} must be a function that takes 2 params: {{(index, column)}}. The first is the integer row index of the listview, and the 2nd is the string column name. The callback should return a string, the path to the {{.ico}} file to be displayed. The file will be cached, so if you change the file on disk, call {{tastudio.clearIconCache()}}.")] - public string OnQueryItemIcon(LuaFunction luaf, string name = null) + public string OnQueryItemIcon(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -679,7 +681,7 @@ public void ClearIconCache() [LuaMethodExample("tastudio.ongreenzoneinvalidated( function( currentindex )\r\n\tconsole.log( \"Called whenever the greenzone is invalidated.\" );\r\nend );")] [LuaMethod("ongreenzoneinvalidated", "Called whenever the movie is modified in a way that could invalidate savestates in the movie's state history. Called regardless of whether any states were actually invalidated. Your callback can have 1 parameter, which will be the last frame before the invalidated ones. That is, the first of the modified frames.")] - public string OnGreenzoneInvalidated(LuaFunction luaf, string name = null) + public string OnGreenzoneInvalidated(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -696,7 +698,7 @@ public string OnGreenzoneInvalidated(LuaFunction luaf, string name = null) [LuaMethodExample("tastudio.onbranchload( function( currentindex )\r\n\tconsole.log( \"Called whenever a branch is loaded.\" );\r\nend );")] [LuaMethod("onbranchload", "called whenever a branch is loaded. luaf must be a function that takes the integer branch index as a parameter")] - public string OnBranchLoad(LuaFunction luaf, string name = null) + public string OnBranchLoad(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -718,7 +720,7 @@ public string OnBranchLoad(LuaFunction luaf, string name = null) name: "onbranchsave", description: "Sets a callback which fires after any branch is created or updated." + DESC_LINE_BRANCH_CHANGE_CB)] - public string OnBranchSave(LuaFunction luaf, string name = null) + public string OnBranchSave(LuaFunction luaf, string? name = null) { if (Engaged()) { @@ -740,7 +742,7 @@ public string OnBranchSave(LuaFunction luaf, string name = null) name: "onbranchremove", description: "Sets a callback which fires after any branch is removed." + DESC_LINE_BRANCH_CHANGE_CB)] - public string OnBranchRemove(LuaFunction luaf, string name = null) + public string OnBranchRemove(LuaFunction luaf, string? name = null) { if (Engaged()) { From 708432e4b94d2c14c23fc1580b69a0d36aa959ac Mon Sep 17 00:00:00 2001 From: kalimag Date: Sat, 18 Apr 2026 07:46:26 +0200 Subject: [PATCH 04/10] Remove unused class --- .../tools/Lua/Libraries/TAStudioLuaLibrary.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs index 13c7881b814..b30134f7d9a 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs @@ -64,13 +64,6 @@ private enum InputChangeTypes Axis, } - public class TastudioBranchInfo - { - public string Id { get; set; } - public int Frame { get; set; } - public string Text { get; set; } - } - private readonly List _changeList = new List(); //TODO: Initialize it to empty list on a script reload, and have each script have it's own list [LuaMethodExample("if ( tastudio.engaged( ) ) then\r\n\tconsole.log( \"returns whether or not tastudio is currently engaged ( active )\" );\r\nend;")] From d85e8c227dbd92d33cd3b164559c471b9eb86541 Mon Sep 17 00:00:00 2001 From: kalimag Date: Sun, 19 Apr 2026 14:47:59 +0200 Subject: [PATCH 05/10] Enable `#nullable` on `CommLuaLibrary` --- .../lua/CommonLibs/CommLuaLibrary.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs index c737852e017..ca13766e169 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -155,7 +157,7 @@ public int MmfCopyFromMemory( string mmf_filename, long addr, int length, - string domain) + string? domain = null) => APIs.Comm.MMF.WriteToFile(mmf_filename, APIs.Memory.ReadByteRange(addr, length, domain).ToArray()); [LuaMethod("mmfCopyToMemory", "Copy a memory mapped file to a section of the memory")] @@ -163,7 +165,7 @@ public void MmfCopyToMemory( string mmf_filename, long addr, int length, - string domain) + string? domain = null) => APIs.Memory.WriteByteRange(addr, APIs.Comm.MMF.ReadBytesFromFile(mmf_filename, length), domain); [LuaMethod("mmfRead", "Reads a string from a memory mapped file")] @@ -177,35 +179,35 @@ public LuaTable MmfReadBytes(string mmf_filename, int expectedSize) // All HTTP related methods [LuaMethod("httpTest", "tests HTTP connections")] - public string HttpTest() + public string? HttpTest() { _ = APIs.Comm.HTTP!; // to match previous behaviour return APIs.Comm.HttpTest(); } [LuaMethod("httpTestGet", "tests the HTTP GET connection")] - public string HttpTestGet() + public string? HttpTestGet() { CheckHttp(); return APIs.Comm.HttpTestGet(); } [LuaMethod("httpGet", "makes a HTTP GET request")] - public string HttpGet(string url) + public string? HttpGet(string url) { CheckHttp(); return APIs.Comm.HTTP?.ExecGet(url); } [LuaMethod("httpPost", "makes a HTTP POST request")] - public string HttpPost(string url, string payload) + public string? HttpPost(string url, string payload) { CheckHttp(); return APIs.Comm.HTTP?.ExecPostAsForm(url: url, payload: payload); } [LuaMethod("httpPostScreenshot", "HTTP POST screenshot")] - public string HttpPostScreenshot() + public string? HttpPostScreenshot() { CheckHttp(); return APIs.Comm.HTTP?.SendScreenshot(); @@ -222,25 +224,25 @@ public void HttpSetTimeout(int timeout) public void HttpSetPostUrl(string url) { CheckHttp(); - APIs.Comm.HTTP.PostUrl = url; + if (APIs.Comm.HTTP is not null) APIs.Comm.HTTP.PostUrl = url; } [LuaMethod("httpSetGetUrl", "Sets HTTP GET URL")] public void HttpSetGetUrl(string url) { CheckHttp(); - APIs.Comm.HTTP.GetUrl = url; + if (APIs.Comm.HTTP is not null) APIs.Comm.HTTP.GetUrl = url; } [LuaMethod("httpGetPostUrl", "Gets HTTP POST URL")] - public string HttpGetPostUrl() + public string? HttpGetPostUrl() { CheckHttp(); return APIs.Comm.HTTP?.PostUrl; } [LuaMethod("httpGetGetUrl", "Gets HTTP GET URL")] - public string HttpGetGetUrl() + public string? HttpGetGetUrl() { CheckHttp(); return APIs.Comm.HTTP?.GetUrl; @@ -257,7 +259,7 @@ private void CheckHttp() #if ENABLE_WEBSOCKETS [LuaMethod("ws_open", "Opens a websocket and returns the id so that it can be retrieved later.")] [LuaMethodExample("local ws_id = comm.ws_open(\"wss://echo.websocket.org\");")] - public string WebSocketOpen(string uri) + public string? WebSocketOpen(string uri) { var wsServer = APIs.Comm.WebSockets; if (wsServer == null) @@ -282,7 +284,7 @@ public void WebSocketSend( [LuaMethod("ws_receive", "Receive a message from a certain websocket id and a maximum number of bytes to read")] [LuaMethodExample("local ws = comm.ws_receive(ws_id, str_len);")] - public string WebSocketReceive(string guid, int bufferCap) + public string? WebSocketReceive(string guid, int bufferCap) => _websockets.TryGetValue(Guid.Parse(guid), out var wrapper) ? wrapper.Receive(bufferCap) : null; From 22815b6c46704f3861969727ed5e8d48018ec2e3 Mon Sep 17 00:00:00 2001 From: kalimag Date: Sun, 19 Apr 2026 14:51:54 +0200 Subject: [PATCH 06/10] Enable `#nullable` on `CommLuaLibrary` (sockets) --- .../lua/CommonLibs/CommLuaLibrary.cs | 55 +++++++------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs index ca13766e169..02164b949fb 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs @@ -32,76 +32,67 @@ public static string GetLuaFunctionsList() } [LuaMethod("socketServerIsConnected", "socketServerIsConnected")] - public bool SocketServerIsConnected() - => APIs.Comm.Sockets.Connected; + public bool? SocketServerIsConnected() + => APIs.Comm.Sockets?.Connected; [LuaMethod("socketServerScreenShot", "sends a screenshot to the Socket server")] - public string SocketServerScreenShot() + public string? SocketServerScreenShot() { - CheckSocketServer(); - return APIs.Comm.Sockets?.SendScreenshot(); + return GetSocketServer()?.SendScreenshot(); } [LuaMethod("socketServerScreenShotResponse", "sends a screenshot to the Socket server and retrieves the response")] - public string SocketServerScreenShotResponse() + public string? SocketServerScreenShotResponse() { - CheckSocketServer(); - return APIs.Comm.Sockets?.SendScreenshot(1000); + return GetSocketServer()?.SendScreenshot(1000); } [LuaMethod("socketServerSend", "sends a string to the Socket server")] public int SocketServerSend(string SendString) { - if (!CheckSocketServer()) - { - return -1; - } - return APIs.Comm.Sockets.SendString(SendString); + return GetSocketServer()?.SendString(SendString) ?? -1; } [LuaMethod("socketServerSendBytes", "sends bytes to the Socket server")] public int SocketServerSendBytes(LuaTable byteArray) { - if (!CheckSocketServer()) return -1; - return APIs.Comm.Sockets.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()); + return GetSocketServer() + ?.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()) + ?? -1; } [LuaMethod("socketServerResponse", "Receives a message from the Socket server. Since BizHawk 2.6.2, all responses must be of the form $\"{msg.Length:D} {msg}\" i.e. prefixed with the length in base-10 and a space.")] - public string SocketServerResponse() + public string? SocketServerResponse() { - CheckSocketServer(); - return APIs.Comm.Sockets?.ReceiveString(); + return GetSocketServer()?.ReceiveString(); } [LuaMethod("socketServerSuccessful", "returns the status of the last Socket server action")] public bool SocketServerSuccessful() { - return CheckSocketServer() && APIs.Comm.Sockets.Successful; + return GetSocketServer()?.Successful ?? false; } [LuaMethod("socketServerSetTimeout", "sets the timeout in milliseconds for receiving messages")] public void SocketServerSetTimeout(int timeout) { - CheckSocketServer(); - APIs.Comm.Sockets?.SetTimeout(timeout); + GetSocketServer()?.SetTimeout(timeout); } [LuaMethod("socketServerSetIp", "sets the IP address of the Lua socket server")] public void SocketServerSetIp(string ip) { - CheckSocketServer(); - APIs.Comm.Sockets.IP = ip; + if (GetSocketServer() is { } sockets) sockets.IP = ip; } [LuaMethod("socketServerSetPort", "sets the port of the Lua socket server")] public void SocketServerSetPort(ushort port) { - CheckSocketServer(); - APIs.Comm.Sockets.Port = port; + if (GetSocketServer() is { } sockets) sockets.Port = port; } [LuaMethod("socketServerGetIp", "returns the IP address of the Lua socket server")] - public string SocketServerGetIp() + public string? SocketServerGetIp() { return APIs.Comm.Sockets?.IP; } @@ -115,20 +106,16 @@ public string SocketServerGetIp() [LuaMethod("socketServerGetInfo", "returns the IP and port of the Lua socket server")] public string SocketServerGetInfo() { - return CheckSocketServer() - ? APIs.Comm.Sockets.GetInfo() - : ""; + return GetSocketServer()?.GetInfo() ?? ""; } - private bool CheckSocketServer() + private SocketServer? GetSocketServer() { - if (APIs.Comm.Sockets == null) + if (APIs.Comm.Sockets is null) { Log("Socket server was not initialized, please initialize it via the command line"); - return false; } - - return true; + return APIs.Comm.Sockets; } // All MemoryMappedFile related methods From 3918e5945968739bf8e5ca25eeda84e49dbb204d Mon Sep 17 00:00:00 2001 From: kalimag Date: Sun, 19 Apr 2026 15:21:43 +0200 Subject: [PATCH 07/10] Minor adjustments --- src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs | 4 ++-- .../lua/LuaHelperLibs/StringLuaLibrary.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs index 8d271e114ad..8162364298b 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/ClientLuaLibrary.cs @@ -420,7 +420,7 @@ public void ExactSleep(int millis) [LuaMethodExample("client.addcheat(\"NNNPAK\");")] [LuaMethod("addcheat", "adds a cheat code, if supported")] - public void AddCheat(string? code) + public void AddCheat(string code) { if (string.IsNullOrWhiteSpace(code)) { @@ -440,7 +440,7 @@ public void AddCheat(string? code) [LuaMethodExample("client.removecheat(\"NNNPAK\");")] [LuaMethod("removecheat", "removes a cheat, if it already exists")] - public void RemoveCheat(string? code) + public void RemoveCheat(string code) { if (string.IsNullOrWhiteSpace(code)) { diff --git a/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs b/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs index 9c051087753..88e6484b9fd 100644 --- a/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/LuaHelperLibs/StringLuaLibrary.cs @@ -114,7 +114,7 @@ public static string PadStart( public static string? Replace( string? str, string str2, - string? replace) + string replace = "") { return string.IsNullOrEmpty(str) ? null From 08b511adb7330a5d2ef244a17c89e6e0ddd510f8 Mon Sep 17 00:00:00 2001 From: kalimag Date: Mon, 20 Apr 2026 07:27:51 +0200 Subject: [PATCH 08/10] Revert "Enable `#nullable` on `CommLuaLibrary` (sockets)" This reverts commit 6adbf5175695d6016120ae7c65fec2968c603661. --- .../lua/CommonLibs/CommLuaLibrary.cs | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs index 02164b949fb..ca13766e169 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs @@ -32,67 +32,76 @@ public static string GetLuaFunctionsList() } [LuaMethod("socketServerIsConnected", "socketServerIsConnected")] - public bool? SocketServerIsConnected() - => APIs.Comm.Sockets?.Connected; + public bool SocketServerIsConnected() + => APIs.Comm.Sockets.Connected; [LuaMethod("socketServerScreenShot", "sends a screenshot to the Socket server")] - public string? SocketServerScreenShot() + public string SocketServerScreenShot() { - return GetSocketServer()?.SendScreenshot(); + CheckSocketServer(); + return APIs.Comm.Sockets?.SendScreenshot(); } [LuaMethod("socketServerScreenShotResponse", "sends a screenshot to the Socket server and retrieves the response")] - public string? SocketServerScreenShotResponse() + public string SocketServerScreenShotResponse() { - return GetSocketServer()?.SendScreenshot(1000); + CheckSocketServer(); + return APIs.Comm.Sockets?.SendScreenshot(1000); } [LuaMethod("socketServerSend", "sends a string to the Socket server")] public int SocketServerSend(string SendString) { - return GetSocketServer()?.SendString(SendString) ?? -1; + if (!CheckSocketServer()) + { + return -1; + } + return APIs.Comm.Sockets.SendString(SendString); } [LuaMethod("socketServerSendBytes", "sends bytes to the Socket server")] public int SocketServerSendBytes(LuaTable byteArray) { - return GetSocketServer() - ?.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()) - ?? -1; + if (!CheckSocketServer()) return -1; + return APIs.Comm.Sockets.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()); } [LuaMethod("socketServerResponse", "Receives a message from the Socket server. Since BizHawk 2.6.2, all responses must be of the form $\"{msg.Length:D} {msg}\" i.e. prefixed with the length in base-10 and a space.")] - public string? SocketServerResponse() + public string SocketServerResponse() { - return GetSocketServer()?.ReceiveString(); + CheckSocketServer(); + return APIs.Comm.Sockets?.ReceiveString(); } [LuaMethod("socketServerSuccessful", "returns the status of the last Socket server action")] public bool SocketServerSuccessful() { - return GetSocketServer()?.Successful ?? false; + return CheckSocketServer() && APIs.Comm.Sockets.Successful; } [LuaMethod("socketServerSetTimeout", "sets the timeout in milliseconds for receiving messages")] public void SocketServerSetTimeout(int timeout) { - GetSocketServer()?.SetTimeout(timeout); + CheckSocketServer(); + APIs.Comm.Sockets?.SetTimeout(timeout); } [LuaMethod("socketServerSetIp", "sets the IP address of the Lua socket server")] public void SocketServerSetIp(string ip) { - if (GetSocketServer() is { } sockets) sockets.IP = ip; + CheckSocketServer(); + APIs.Comm.Sockets.IP = ip; } [LuaMethod("socketServerSetPort", "sets the port of the Lua socket server")] public void SocketServerSetPort(ushort port) { - if (GetSocketServer() is { } sockets) sockets.Port = port; + CheckSocketServer(); + APIs.Comm.Sockets.Port = port; } [LuaMethod("socketServerGetIp", "returns the IP address of the Lua socket server")] - public string? SocketServerGetIp() + public string SocketServerGetIp() { return APIs.Comm.Sockets?.IP; } @@ -106,16 +115,20 @@ public void SocketServerSetPort(ushort port) [LuaMethod("socketServerGetInfo", "returns the IP and port of the Lua socket server")] public string SocketServerGetInfo() { - return GetSocketServer()?.GetInfo() ?? ""; + return CheckSocketServer() + ? APIs.Comm.Sockets.GetInfo() + : ""; } - private SocketServer? GetSocketServer() + private bool CheckSocketServer() { - if (APIs.Comm.Sockets is null) + if (APIs.Comm.Sockets == null) { Log("Socket server was not initialized, please initialize it via the command line"); + return false; } - return APIs.Comm.Sockets; + + return true; } // All MemoryMappedFile related methods From 2e8644af1814c3cb33b70068d27796f5751e37b7 Mon Sep 17 00:00:00 2001 From: kalimag Date: Mon, 20 Apr 2026 07:33:22 +0200 Subject: [PATCH 09/10] Enable `#nullable` on `CommLuaLibrary` (annotations only) --- .../lua/CommonLibs/CommLuaLibrary.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs index ca13766e169..5220418efe4 100644 --- a/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs +++ b/src/BizHawk.Client.Common/lua/CommonLibs/CommLuaLibrary.cs @@ -33,17 +33,17 @@ public static string GetLuaFunctionsList() [LuaMethod("socketServerIsConnected", "socketServerIsConnected")] public bool SocketServerIsConnected() - => APIs.Comm.Sockets.Connected; + => APIs.Comm.Sockets!.Connected; [LuaMethod("socketServerScreenShot", "sends a screenshot to the Socket server")] - public string SocketServerScreenShot() + public string? SocketServerScreenShot() { CheckSocketServer(); return APIs.Comm.Sockets?.SendScreenshot(); } [LuaMethod("socketServerScreenShotResponse", "sends a screenshot to the Socket server and retrieves the response")] - public string SocketServerScreenShotResponse() + public string? SocketServerScreenShotResponse() { CheckSocketServer(); return APIs.Comm.Sockets?.SendScreenshot(1000); @@ -56,18 +56,18 @@ public int SocketServerSend(string SendString) { return -1; } - return APIs.Comm.Sockets.SendString(SendString); + return APIs.Comm.Sockets!.SendString(SendString); } [LuaMethod("socketServerSendBytes", "sends bytes to the Socket server")] public int SocketServerSendBytes(LuaTable byteArray) { if (!CheckSocketServer()) return -1; - return APIs.Comm.Sockets.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()); + return APIs.Comm.Sockets!.SendBytes(_th.EnumerateValues(byteArray).Select(l => (byte) l).ToArray()); } [LuaMethod("socketServerResponse", "Receives a message from the Socket server. Since BizHawk 2.6.2, all responses must be of the form $\"{msg.Length:D} {msg}\" i.e. prefixed with the length in base-10 and a space.")] - public string SocketServerResponse() + public string? SocketServerResponse() { CheckSocketServer(); return APIs.Comm.Sockets?.ReceiveString(); @@ -76,7 +76,7 @@ public string SocketServerResponse() [LuaMethod("socketServerSuccessful", "returns the status of the last Socket server action")] public bool SocketServerSuccessful() { - return CheckSocketServer() && APIs.Comm.Sockets.Successful; + return CheckSocketServer() && APIs.Comm.Sockets!.Successful; } [LuaMethod("socketServerSetTimeout", "sets the timeout in milliseconds for receiving messages")] @@ -90,18 +90,18 @@ public void SocketServerSetTimeout(int timeout) public void SocketServerSetIp(string ip) { CheckSocketServer(); - APIs.Comm.Sockets.IP = ip; + APIs.Comm.Sockets!.IP = ip; } [LuaMethod("socketServerSetPort", "sets the port of the Lua socket server")] public void SocketServerSetPort(ushort port) { CheckSocketServer(); - APIs.Comm.Sockets.Port = port; + APIs.Comm.Sockets!.Port = port; } [LuaMethod("socketServerGetIp", "returns the IP address of the Lua socket server")] - public string SocketServerGetIp() + public string? SocketServerGetIp() { return APIs.Comm.Sockets?.IP; } @@ -116,7 +116,7 @@ public string SocketServerGetIp() public string SocketServerGetInfo() { return CheckSocketServer() - ? APIs.Comm.Sockets.GetInfo() + ? APIs.Comm.Sockets!.GetInfo() : ""; } From fc08f683eaf0c4220ca02132a0694a2126e1fd8f Mon Sep 17 00:00:00 2001 From: kalimag Date: Sun, 26 Apr 2026 00:02:49 +0200 Subject: [PATCH 10/10] Enable `#nullabe` on `LuaCanvas` and `LuaPictureBox` Also make `_defaultTextBackground` non-nullable --- .../tools/Lua/LuaCanvas.cs | 54 ++++++++++--------- .../tools/Lua/LuaPictureBox.cs | 48 +++++++++-------- 2 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaCanvas.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaCanvas.cs index 982d0e0436c..ae9d3f533bd 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaCanvas.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaCanvas.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.ComponentModel; using System.Drawing; using System.Windows.Forms; @@ -179,8 +181,8 @@ public void DrawBox( int y, int x2, int y2, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -202,8 +204,8 @@ public void DrawEllipse( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -310,7 +312,7 @@ public void DrawImageRegion( [LuaMethod( "DrawLine", "Draws a line from the first coordinate pair to the 2nd. Color is optional (if not specified it will be drawn black)")] - public void DrawLine(int x1, int y1, int x2, int y2, [LuaColorParam] object color = null) + public void DrawLine(int x1, int y1, int x2, int y2, [LuaColorParam] object? color = null) { luaPictureBox.DrawLine(x1, y1, x2, y2, _th.SafeParseColor(color)); } @@ -320,7 +322,7 @@ public void DrawLine(int x1, int y1, int x2, int y2, [LuaColorParam] object colo [LuaMethod( "DrawAxis", "Draws an axis of the specified size at the coordinate pair.)")] - public void DrawAxis(int x, int y, int size, [LuaColorParam] object color = null) + public void DrawAxis(int x, int y, int size, [LuaColorParam] object? color = null) { luaPictureBox.DrawAxis(x, y, size, _th.SafeParseColor(color)); } @@ -338,7 +340,7 @@ public void DrawArc( int height, int startAngle, int sweepAngle, - [LuaColorParam] object line = null) + [LuaColorParam] object? line = null) { luaPictureBox.DrawArc(x, y, width, height, startAngle, sweepAngle, _th.SafeParseColor(line)); } @@ -355,8 +357,8 @@ public void DrawPie( int height, int startAngle, int sweepAngle, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { luaPictureBox.DrawPie(x, y, width, height, startAngle, sweepAngle, _th.SafeParseColor(line), _th.SafeParseColor(background)); } @@ -366,7 +368,7 @@ public void DrawPie( [LuaMethod( "DrawPixel", "Draws a single pixel at the given coordinates in the given color. Color is optional (if not specified it will be drawn black)")] - public void DrawPixel(int x, int y, [LuaColorParam] object color = null) + public void DrawPixel(int x, int y, [LuaColorParam] object? color = null) { try { @@ -392,8 +394,8 @@ public void DrawPolygon( LuaTable points, int? x = null, int? y = null, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { try { @@ -416,8 +418,8 @@ public void DrawRectangle( int y, int width, int height, - [LuaColorParam] object line = null, - [LuaColorParam] object background = null) + [LuaColorParam] object? line = null, + [LuaColorParam] object? background = null) { luaPictureBox.DrawRectangle(x, y, width, height, _th.SafeParseColor(line), _th.SafeParseColor(background)); } @@ -431,13 +433,13 @@ public void DrawString( int x, int y, string message, - [LuaColorParam] object foreColor = null, - [LuaColorParam] object backColor = null, + [LuaColorParam] object? foreColor = null, + [LuaColorParam] object? backColor = null, int? fontSize = null, - string fontFamily = null, - string fontStyle = null, - string horizontalAlign = null, - string verticalAlign = null) + string? fontFamily = null, + string? fontStyle = null, + string? horizontalAlign = null, + string? verticalAlign = null) { luaPictureBox.DrawText(x, y, message, _th.SafeParseColor(foreColor), _th.SafeParseColor(backColor), fontSize, fontFamily, fontStyle, horizontalAlign, verticalAlign); } @@ -451,13 +453,13 @@ public void DrawText( int x, int y, string message, - [LuaColorParam] object foreColor = null, - [LuaColorParam] object backColor = null, + [LuaColorParam] object? foreColor = null, + [LuaColorParam] object? backColor = null, int? fontSize = null, - string fontFamily = null, - string fontStyle = null, - string horizontalAlign = null, - string verticalAlign = null) + string? fontFamily = null, + string? fontStyle = null, + string? horizontalAlign = null, + string? verticalAlign = null) { luaPictureBox.DrawText(x, y, message, _th.SafeParseColor(foreColor), _th.SafeParseColor(backColor), fontSize, fontFamily, fontStyle, horizontalAlign, verticalAlign); } diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs index 3e1ba9268ae..a47fc7cc678 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -36,7 +38,7 @@ private Pen GetPen([LuaColorParam] object color) private Color _defaultForeground = Color.Black; private Color? _defaultBackground; - private Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); + private Color _defaultTextBackground = Color.FromArgb(128, 0, 0, 0); public LuaPictureBox(NLuaTableHelper tableHelper, Action logOutputCallback) { @@ -98,8 +100,8 @@ public void DrawBox( int y, int x2, int y2, - [LuaColorParam] object line, - [LuaColorParam] object background) + [LuaColorParam] object? line, + [LuaColorParam] object? background) { if (x < x2) { @@ -137,8 +139,8 @@ public void DrawEllipse( int y, int width, int height, - [LuaColorParam] object line, - [LuaColorParam] object background) + [LuaColorParam] object? line, + [LuaColorParam] object? background) { var bg = TableHelper.SafeParseColor(background) ?? _defaultBackground; var boxBackground = Graphics.FromImage(Image); @@ -212,13 +214,13 @@ public void DrawImageRegion( boxBackground.DrawImage(img, destRect, sourceX, sourceY, sourceWidth, sourceHeight, GraphicsUnit.Pixel); } - public void DrawLine(int x1, int y1, int x2, int y2, [LuaColorParam] object color) + public void DrawLine(int x1, int y1, int x2, int y2, [LuaColorParam] object? color) { var boxBackground = Graphics.FromImage(Image); boxBackground.DrawLine(GetPen(TableHelper.SafeParseColor(color) ?? _defaultForeground), x1, y1, x2, y2); } - public void DrawAxis(int x, int y, int size, [LuaColorParam] object color) + public void DrawAxis(int x, int y, int size, [LuaColorParam] object? color) { var color1 = TableHelper.SafeParseColor(color); DrawLine(x + size, y, x - size, y, color1); @@ -232,7 +234,7 @@ public void DrawArc( int height, int startAngle, int sweepAngle, - [LuaColorParam] object line) + [LuaColorParam] object? line) { var boxBackground = Graphics.FromImage(Image); boxBackground.DrawArc(GetPen(TableHelper.SafeParseColor(line) ?? _defaultForeground), x, y, width, height, startAngle, sweepAngle); @@ -245,8 +247,8 @@ public void DrawPie( int height, int startAngle, int sweepAngle, - [LuaColorParam] object line, - [LuaColorParam] object background) + [LuaColorParam] object? line, + [LuaColorParam] object? background) { var bg = TableHelper.SafeParseColor(background) ?? _defaultBackground; var boxBackground = Graphics.FromImage(Image); @@ -260,7 +262,7 @@ public void DrawPie( boxBackground.DrawPie(GetPen(TableHelper.SafeParseColor(line) ?? _defaultForeground), x + 1, y + 1, width - 1, height - 1, startAngle, sweepAngle); } - public void DrawPixel(int x, int y, [LuaColorParam] object color) + public void DrawPixel(int x, int y, [LuaColorParam] object? color) { var boxBackground = Graphics.FromImage(Image); boxBackground.DrawLine(GetPen(TableHelper.SafeParseColor(color) ?? _defaultForeground), x, y, x + 0.1F, y); @@ -270,8 +272,8 @@ public void DrawPolygon( LuaTable points, int? x, int? y, - [LuaColorParam] object line, - [LuaColorParam] object background) + [LuaColorParam] object? line, + [LuaColorParam] object? background) { var pointsList = TableHelper.EnumerateValues(points) .Select(table => TableHelper.EnumerateValues(table).ToList()).ToList(); @@ -299,8 +301,8 @@ public void DrawRectangle( int y, int width, int height, - [LuaColorParam] object line, - [LuaColorParam] object background) + [LuaColorParam] object? line, + [LuaColorParam] object? background) { var bg = TableHelper.SafeParseColor(background) ?? _defaultBackground; var boxBackground = Graphics.FromImage(Image); @@ -317,13 +319,13 @@ public void DrawText( int x, int y, string message, - [LuaColorParam] object foreColor, - [LuaColorParam] object backColor, + [LuaColorParam] object? foreColor, + [LuaColorParam] object? backColor, int? fontSize, - string fontFamily, - string fontStyle, - string horizAlign, - string vertAlign) + string? fontFamily, + string? fontStyle, + string? horizAlign, + string? vertAlign) { var family = FontFamily.GenericMonospace; if (fontFamily != null) @@ -395,7 +397,7 @@ public void DrawText( } Rectangle rect = new Rectangle(new Point(x, y), sizeOfText); boxBackground = Graphics.FromImage(Image); - boxBackground.FillRectangle(GetBrush(TableHelper.SafeParseColor(backColor) ?? _defaultTextBackground.Value), rect); + boxBackground.FillRectangle(GetBrush(TableHelper.SafeParseColor(backColor) ?? _defaultTextBackground), rect); boxBackground = Graphics.FromImage(Image); boxBackground.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; boxBackground.DrawString(message, font, GetBrush(TableHelper.SafeParseColor(foreColor) ?? Color.Black), x, y); @@ -409,7 +411,7 @@ public Point GetMouse() private void DoLuaClick(object sender, EventArgs e) { - LuaWinform parent = Parent as LuaWinform; + LuaWinform? parent = Parent as LuaWinform; parent?.DoLuaEvent(Handle); }