Skip to content

Commit 0bc5861

Browse files
committed
dsda: custom hook for P_Random()
Revert "Replace 2 `ILuaLibraries` methods with delegates on `EventsLuaLibrary`" This reverts commit a85ef40. reverting that one because it made it more painful to add custom hooks
1 parent cb0b2d6 commit 0bc5861

File tree

12 files changed

+116
-41
lines changed

12 files changed

+116
-41
lines changed

Assets/dll/dsda.wbx.zst

-7.24 KB
Binary file not shown.

src/BizHawk.Client.Common/lua/ILuaLibraries.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using NLua;
2+
13
namespace BizHawk.Client.Common
24
{
35
public interface ILuaLibraries
@@ -12,6 +14,15 @@ public interface ILuaLibraries
1214

1315
PathEntryCollection PathEntries { get; }
1416

17+
INamedLuaFunction CreateAndRegisterNamedFunction(
18+
LuaFunction function,
19+
string theEvent,
20+
Action<string> logCallback,
21+
LuaFile luaFile,
22+
string name = null);
23+
1524
NLuaTableHelper GetTableHelper();
25+
26+
bool RemoveNamedFunctionMatching(Func<INamedLuaFunction, bool> predicate);
1627
}
1728
}

src/BizHawk.Client.Common/lua/INamedLuaFunction.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public interface INamedLuaFunction
1212

1313
MemoryCallbackDelegate MemCallback { get; }
1414

15+
Action<int> RandomCallback { get; }
16+
1517
string Name { get; }
1618

1719
Action OnRemove { get; set; }
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.ComponentModel;
2+
3+
using BizHawk.Emulation.Common;
4+
using BizHawk.Emulation.Cores;
5+
using BizHawk.Emulation.Cores.Computers.Doom;
6+
7+
using NLua;
8+
9+
// ReSharper disable UnusedMember.Global
10+
// ReSharper disable UnusedAutoPropertyAccessor.Local
11+
namespace BizHawk.Client.Common
12+
{
13+
[Description("Functions specific to Doom games (functions may not run when a Doom game is not loaded)")]
14+
public sealed class DoomLuaLibrary : LuaLibraryBase
15+
{
16+
public DoomLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action<string> logOutputCallback)
17+
: base(luaLibsImpl, apiContainer, logOutputCallback) { }
18+
19+
public override string Name => "doom";
20+
private const string ERR_MSG_UNSUPPORTED_CORE = $"`doom.*` functions can only be used with {CoreNames.DSDA}";
21+
22+
[RequiredService]
23+
private IEmulator Emulator { get; set; }
24+
25+
/// <exception cref="InvalidOperationException">loaded core is not DSDA-Doom</exception>
26+
[LuaMethodExample("local rngcall = doom.onprandom(\r\n\tfunction()\r\n\t\tconsole.log( \"Calls the given lua function after each P_Random() call by Doom\" );\r\n\tend\r\n\t, \"Frame name\" );")]
27+
[LuaMethod("onprandom", "Calls the given lua function after each P_Random() call by Doom")]
28+
public string OnPrandom(LuaFunction luaf, string name = null)
29+
{
30+
if (Emulator is not DSDA)
31+
{
32+
throw new InvalidOperationException(ERR_MSG_UNSUPPORTED_CORE);
33+
}
34+
35+
var callbacks = (Emulator as DSDA).RandomCallbacks;
36+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, "OnPrandom", LogOutputCallback, CurrentFile, name: name);
37+
callbacks.Add(nlf.RandomCallback);
38+
nlf.OnRemove += () => callbacks.Remove(nlf.RandomCallback);
39+
return nlf.GuidStr;
40+
}
41+
}
42+
}

src/BizHawk.Client.Common/lua/LuaHelperLibs/EventsLuaLibrary.cs

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,8 @@ namespace BizHawk.Client.Common
1111
[Description("A library for registering lua functions to emulator events.\n All events support multiple registered methods.\nAll registered event methods can be named and return a Guid when registered")]
1212
public sealed class EventsLuaLibrary : LuaLibraryBase
1313
{
14-
public delegate INamedLuaFunction NLFAddCallback(
15-
LuaFunction function,
16-
string theEvent,
17-
Action<string> logCallback,
18-
LuaFile luaFile,
19-
string name = null);
20-
21-
public delegate bool NLFRemoveCallback(Func<INamedLuaFunction, bool> predicate);
22-
2314
private static readonly string EMPTY_UUID_STR = Guid.Empty.ToString("D");
2415

25-
public NLFAddCallback CreateAndRegisterNamedFunction { get; set; }
26-
27-
public NLFRemoveCallback RemoveNamedFunctionMatching { get; set; }
28-
2916
[OptionalService]
3017
private IInputPollable InputPollableCore { get; set; }
3118

@@ -75,20 +62,20 @@ public bool CanUseCallbackParams(string subset = null)
7562
[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\" );")]
7663
[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")]
7764
public string OnFrameEnd(LuaFunction luaf, string name = null)
78-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_POSTFRAME, LogOutputCallback, CurrentFile, name: name)
65+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_POSTFRAME, LogOutputCallback, CurrentFile, name)
7966
.GuidStr;
8067

8168
[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\" );")]
8269
[LuaMethod("onframestart", "Calls the given lua function at the beginning of each frame before any emulation and drawing occurs")]
8370
public string OnFrameStart(LuaFunction luaf, string name = null)
84-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_PREFRAME, LogOutputCallback, CurrentFile, name: name)
71+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_PREFRAME, LogOutputCallback, CurrentFile, name)
8572
.GuidStr;
8673

8774
[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\" );")]
8875
[LuaMethod("oninputpoll", "Calls the given lua function after each time the emulator core polls for input")]
8976
public string OnInputPoll(LuaFunction luaf, string name = null)
9077
{
91-
var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_INPUTPOLL, LogOutputCallback, CurrentFile, name: name);
78+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_INPUTPOLL, LogOutputCallback, CurrentFile, name);
9279
//TODO should we bother registering the function if the service isn't supported? none of the other events work this way --yoshi
9380

9481
if (InputPollableCore != null)
@@ -119,7 +106,7 @@ private void LogNotImplemented()
119106
[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\" );")]
120107
[LuaMethod("onloadstate", "Fires after a state is loaded. Your callback can have 1 parameter, which will be the name of the loaded state.")]
121108
public string OnLoadState(LuaFunction luaf, string name = null)
122-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_LOADSTATE, LogOutputCallback, CurrentFile, name: name)
109+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_LOADSTATE, LogOutputCallback, CurrentFile, name)
123110
.GuidStr;
124111

125112
[LuaDeprecatedMethod]
@@ -154,7 +141,7 @@ public string OnBusExec(
154141
return EMPTY_UUID_STR;
155142
}
156143

157-
var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMEXEC, LogOutputCallback, CurrentFile, name: name);
144+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMEXEC, LogOutputCallback, CurrentFile, name);
158145
AddMemCallbackOnCore(nlf, MemoryCallbackType.Execute, scope, address);
159146
return nlf.GuidStr;
160147
}
@@ -198,7 +185,7 @@ public string OnBusExecAny(
198185
return EMPTY_UUID_STR;
199186
}
200187

201-
var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMEXECANY, LogOutputCallback, CurrentFile, name: name);
188+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMEXECANY, LogOutputCallback, CurrentFile, name);
202189
AddMemCallbackOnCore(nlf, MemoryCallbackType.Execute, scope, address: null);
203190
return nlf.GuidStr;
204191
}
@@ -242,7 +229,7 @@ public string OnBusRead(
242229
return EMPTY_UUID_STR;
243230
}
244231

245-
var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMREAD, LogOutputCallback, CurrentFile, name: name);
232+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMREAD, LogOutputCallback, CurrentFile, name);
246233
AddMemCallbackOnCore(nlf, MemoryCallbackType.Read, scope, address);
247234
return nlf.GuidStr;
248235
}
@@ -287,7 +274,7 @@ public string OnBusWrite(
287274
return EMPTY_UUID_STR;
288275
}
289276

290-
var nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMWRITE, LogOutputCallback, CurrentFile, name: name);
277+
var nlf = _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_MEMWRITE, LogOutputCallback, CurrentFile, name);
291278
AddMemCallbackOnCore(nlf, MemoryCallbackType.Write, scope, address);
292279
return nlf.GuidStr;
293280
}
@@ -305,33 +292,33 @@ public string OnBusWrite(
305292
[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\" );")]
306293
[LuaMethod("onsavestate", "Fires after a state is saved. Your callback can have 1 parameter, which will be the name of the saved state.")]
307294
public string OnSaveState(LuaFunction luaf, string name = null)
308-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_SAVESTATE, LogOutputCallback, CurrentFile, name: name)
295+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_SAVESTATE, LogOutputCallback, CurrentFile, name)
309296
.GuidStr;
310297

311298
[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\" );")]
312299
[LuaMethod("onexit", "Fires after the calling script has stopped")]
313300
public string OnExit(LuaFunction luaf, string name = null)
314-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_ENGINESTOP, LogOutputCallback, CurrentFile, name: name)
301+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_ENGINESTOP, LogOutputCallback, CurrentFile, name)
315302
.GuidStr;
316303

317304
[LuaMethodExample("local closeGuid = event.onconsoleclose(\r\n\tfunction()\r\n\t\tconsole.log( \"Fires when the emulator console closes\" );\r\n\tend\r\n\t, \"Frame name\" );")]
318305
[LuaMethod("onconsoleclose", "Fires when the emulator console closes")]
319306
public string OnConsoleClose(LuaFunction luaf, string name = null)
320-
=> CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_CONSOLECLOSE, LogOutputCallback, CurrentFile, name: name)
307+
=> _luaLibsImpl.CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_CONSOLECLOSE, LogOutputCallback, CurrentFile, name)
321308
.GuidStr;
322309

323310
[LuaMethodExample("if ( event.unregisterbyid( \"4d1810b7 - 0d28 - 4acb - 9d8b - d87721641551\" ) ) then\r\n\tconsole.log( \"Removes the registered function that matches the guid.If a function is found and remove the function will return true.If unable to find a match, the function will return false.\" );\r\nend;")]
324311
[LuaMethod("unregisterbyid", "Removes the registered function that matches the guid. If a function is found and remove the function will return true. If unable to find a match, the function will return false.")]
325312
public bool UnregisterById(string guid)
326313
{
327314
Guid parsed = new(guid);
328-
return RemoveNamedFunctionMatching(nlf => nlf.Guid == parsed);
315+
return _luaLibsImpl.RemoveNamedFunctionMatching(nlf => nlf.Guid == parsed);
329316
}
330317

331318
[LuaMethodExample("if ( event.unregisterbyname( \"Function name\" ) ) then\r\n\tconsole.log( \"Removes the first registered function that matches Name.If a function is found and remove the function will return true.If unable to find a match, the function will return false.\" );\r\nend;")]
332319
[LuaMethod("unregisterbyname", "Removes the first registered function that matches Name. If a function is found and remove the function will return true. If unable to find a match, the function will return false.")]
333320
public bool UnregisterByName(string name)
334-
=> RemoveNamedFunctionMatching(nlf => nlf.Name == name);
321+
=> _luaLibsImpl.RemoveNamedFunctionMatching(nlf => nlf.Name == name);
335322

336323
[LuaMethodExample("local scopes = event.availableScopes();")]
337324
[LuaMethod("availableScopes", "Lists the available scopes that can be specified for on_bus_* events")]

src/BizHawk.Client.Common/lua/NamedLuaFunction.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ public NamedLuaFunction(LuaFunction function, string theEvent, Action<string> lo
9393
luaLibraries.IsInInputOrMemoryCallback = false;
9494
}
9595
};
96+
RandomCallback = (pr_class) =>
97+
{
98+
luaLibraries.IsInInputOrMemoryCallback = true;
99+
try
100+
{
101+
Callback([pr_class]);
102+
}
103+
finally
104+
{
105+
luaLibraries.IsInInputOrMemoryCallback = false;
106+
}
107+
};
96108
}
97109

98110
public void DetachFromScript()
@@ -125,6 +137,8 @@ public string GuidStr
125137

126138
public MemoryCallbackDelegate MemCallback { get; }
127139

140+
public Action<int> RandomCallback { get; }
141+
128142
public void Call(string name = null)
129143
{
130144
LuaSandbox.Sandbox(LuaFile.Thread, () =>

src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,6 @@ void EnumerateLuaFunctions(string name, Type type, LuaLibraryBase instance)
9797
consoleLib.Tools = _mainForm.Tools;
9898
_logToLuaConsoleCallback = consoleLib.Log;
9999
}
100-
else if (instance is EventsLuaLibrary eventsLib)
101-
{
102-
eventsLib.CreateAndRegisterNamedFunction = CreateAndRegisterNamedFunction;
103-
eventsLib.RemoveNamedFunctionMatching = RemoveNamedFunctionMatching;
104-
}
105100
else if (instance is FormsLuaLibrary formsLib)
106101
{
107102
formsLib.MainForm = _mainForm;
@@ -309,7 +304,7 @@ public void Close()
309304
_lua = null;
310305
}
311306

312-
private INamedLuaFunction CreateAndRegisterNamedFunction(
307+
public INamedLuaFunction CreateAndRegisterNamedFunction(
313308
LuaFunction function,
314309
string theEvent,
315310
Action<string> logCallback,
@@ -321,7 +316,7 @@ private INamedLuaFunction CreateAndRegisterNamedFunction(
321316
return nlf;
322317
}
323318

324-
private bool RemoveNamedFunctionMatching(Func<INamedLuaFunction, bool> predicate)
319+
public bool RemoveNamedFunctionMatching(Func<INamedLuaFunction, bool> predicate)
325320
{
326321
if (RegisteredFunctions.FirstOrDefault(predicate) is not NamedLuaFunction nlf) return false;
327322
RegisteredFunctions.Remove(nlf);

src/BizHawk.Emulation.Cores/Computers/Doom/DSDA.IEmulator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ public bool FrameAdvance(IController controller, bool renderVideo, bool renderAu
257257
RenderVideo = Convert.ToInt32(renderVideo)
258258
};
259259

260+
_core.dsda_set_random_callback(RandomCallbacks.Count > 0 ? _randomCallback : null);
261+
260262
IsLagFrame = _core.dsda_frame_advance(
261263
automapButtons,
262264
players,

src/BizHawk.Emulation.Cores/Computers/Doom/DSDA.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ public DSDA(CoreLoadParameters<DoomSettings, DoomSyncSettings> lp)
139139
}
140140
}
141141

142+
_randomCallback = (pr_class) =>
143+
{
144+
if (RandomCallbacks.Count > 0)
145+
{
146+
foreach (var cb in RandomCallbacks)
147+
{
148+
cb(pr_class);
149+
}
150+
}
151+
};
152+
142153
_elf = new WaterboxHost(new WaterboxOptions
143154
{
144155
Path = PathUtils.DllDirectoryPath,
@@ -156,7 +167,7 @@ public DSDA(CoreLoadParameters<DoomSettings, DoomSyncSettings> lp)
156167
{
157168
var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(
158169
[
159-
_loadCallback
170+
_loadCallback, _randomCallback
160171
], _elf);
161172

162173
using (_elf.EnterExit())
@@ -250,6 +261,8 @@ public DSDA(CoreLoadParameters<DoomSettings, DoomSyncSettings> lp)
250261
}
251262

252263
ControllerDefinition = CreateControllerDefinition(_syncSettings);
264+
265+
_core.dsda_set_random_callback(RandomCallbacks.Count > 0 ? _randomCallback : null);
253266
}
254267
catch
255268
{
@@ -347,6 +360,9 @@ private static bool PlayerPresent(DoomSyncSettings syncSettings, int port) =>
347360
private List<IRomAsset> _wadFiles;
348361
private List<IRomAsset> _pwadFiles;
349362
private LibDSDA.GameMode _gameMode;
363+
private LibDSDA.random_cb _randomCallback;
364+
365+
public List<Action<int>> RandomCallbacks = [ ];
350366

351367
public string RomDetails { get; } // IRomInfo
352368

src/BizHawk.Emulation.Cores/Computers/Doom/LibDSDA.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,11 @@ public abstract bool dsda_frame_advance(
147147
PackedPlayerInput[] playerInputs,
148148
ref PackedPlayerInput walkcamInputs,
149149
ref PackedRenderInfo renderInfo);
150+
151+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
152+
public delegate void random_cb(int pr_class);
153+
154+
[BizImport(CallingConvention.Cdecl)]
155+
public abstract void dsda_set_random_callback(random_cb cb);
150156
}
151157
}

0 commit comments

Comments
 (0)