prevent various apis from being used while in an input/memory callback

This commit is contained in:
CasualPokePlayer 2024-03-10 23:18:55 -07:00
parent 986299c52b
commit 5bf9d387b4
8 changed files with 122 additions and 10 deletions

View File

@ -74,6 +74,11 @@ namespace BizHawk.Client.Common
[LuaMethod("closerom", "Closes the loaded Rom")]
public void CloseRom()
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("client.closerom() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsRebootingCore = true;
APIs.EmuClient.CloseRom();
_luaLibsImpl.IsRebootingCore = false;
@ -102,6 +107,11 @@ namespace BizHawk.Client.Common
[LuaMethod("seekframe", "Makes the emulator seek to the frame specified")]
public void SeekFrame(int frame)
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("client.seekframe() is not allowed during input/memory callbacks");
}
if (frame < Emulator.Frame)
{
Log("client.seekframe: cannot seek backwards");
@ -200,6 +210,11 @@ namespace BizHawk.Client.Common
[LuaMethod("openrom", "Loads a ROM from the given path. Returns true if the ROM was successfully loaded, otherwise false.")]
public bool OpenRom(string path)
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("client.openrom() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsRebootingCore = true;
var success = APIs.EmuClient.OpenRom(path);
_luaLibsImpl.IsRebootingCore = false;
@ -235,6 +250,11 @@ namespace BizHawk.Client.Common
[LuaMethod("reboot_core", "Reboots the currently loaded core")]
public void RebootCore()
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("client.reboot_core() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsRebootingCore = true;
APIs.EmuClient.RebootCore();
_luaLibsImpl.IsRebootingCore = false;

View File

@ -14,21 +14,35 @@ namespace BizHawk.Client.Common
[LuaMethodExample("local mmsvstsvcst = memorysavestate.savecorestate( );")]
[LuaMethod("savecorestate", "creates a core savestate and stores it in memory. Note: a core savestate is only the raw data from the core, and not extras such as movie input logs, or framebuffers. Returns a unique identifer for the savestate")]
public string SaveCoreStateToMemory()
=> APIs.MemorySaveState.SaveCoreStateToMemory();
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("memorysavestate.savecorestate() is not allowed during input/memory callbacks");
}
return APIs.MemorySaveState!.SaveCoreStateToMemory();
}
[LuaMethodExample("memorysavestate.loadcorestate( \"3fcf120f-0778-43fd-b2c5-460fb7d34184\" );")]
[LuaMethod("loadcorestate", "loads an in memory state with the given identifier")]
public void LoadCoreStateFromMemory(string identifier)
=> APIs.MemorySaveState.LoadCoreStateFromMemory(identifier);
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("memorysavestate.loadcorestate() is not allowed during input/memory callbacks");
}
APIs.MemorySaveState!.LoadCoreStateFromMemory(identifier);
}
[LuaMethodExample("memorysavestate.removestate( \"3fcf120f-0778-43fd-b2c5-460fb7d34184\" );")]
[LuaMethod("removestate", "removes the savestate with the given identifier from memory")]
public void DeleteState(string identifier)
=> APIs.MemorySaveState.DeleteState(identifier);
=> APIs.MemorySaveState!.DeleteState(identifier);
[LuaMethodExample("memorysavestate.clearstatesfrommemory( );")]
[LuaMethod("clearstatesfrommemory", "clears all savestates stored in memory")]
public void ClearInMemoryStates()
=> APIs.MemorySaveState.ClearInMemoryStates();
=> APIs.MemorySaveState!.ClearInMemoryStates();
}
}

View File

@ -71,6 +71,11 @@ namespace BizHawk.Client.Common
[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 = "")
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("movie.play_from_start() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsRebootingCore = true;
var success = APIs.Movie.PlayFromStart(path);
_luaLibsImpl.IsRebootingCore = false;

View File

@ -13,6 +13,11 @@ namespace BizHawk.Client.Common
[LuaMethod("load", "Loads a savestate with the given path. Returns true iff succeeded. If EmuHawk is deferring quicksaves, to TAStudio for example, that form will do what it likes (and the path is ignored).")]
public bool Load(string path, bool suppressOSD = false)
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("savestate.load() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsUpdateSupressed = true;
var success = APIs.SaveState.Load(path, suppressOSD);
_luaLibsImpl.IsUpdateSupressed = false;
@ -23,6 +28,11 @@ namespace BizHawk.Client.Common
[LuaMethod("loadslot", "Loads the savestate at the given slot number (must be an integer between 1 and 10). Returns true iff succeeded. If EmuHawk is deferring quicksaves, to TAStudio for example, that form will do what it likes with the slot number.")]
public bool LoadSlot(int slotNum, bool suppressOSD = false)
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("savestate.loadslot() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsUpdateSupressed = true;
var success = APIs.SaveState.LoadSlot(slotNum, suppressOSD: suppressOSD);
_luaLibsImpl.IsUpdateSupressed = false;
@ -32,11 +42,25 @@ namespace BizHawk.Client.Common
[LuaMethodExample("savestate.save( \"C:\\state.bin\" );")]
[LuaMethod("save", "Saves a state at the given path. If EmuHawk is deferring quicksaves, to TAStudio for example, that form will do what it likes (and the path is ignored).")]
public void Save(string path, bool suppressOSD = false)
=> APIs.SaveState.Save(path, suppressOSD);
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("savestate.save() is not allowed during input/memory callbacks");
}
APIs.SaveState.Save(path, suppressOSD);
}
[LuaMethodExample("savestate.saveslot( 7 );")]
[LuaMethod("saveslot", "Saves a state at the given save slot (must be an integer between 1 and 10). If EmuHawk is deferring quicksaves, to TAStudio for example, that form will do what it likes with the slot number.")]
public void SaveSlot(int slotNum, bool suppressOSD = false)
=> APIs.SaveState.SaveSlot(slotNum, suppressOSD);
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("savestate.saveslot() is not allowed during input/memory callbacks");
}
APIs.SaveState.SaveSlot(slotNum, suppressOSD);
}
}
}

View File

@ -17,6 +17,9 @@ namespace BizHawk.Client.Common
bool IsUpdateSupressed { get; set; }
/// <remarks>not really sure if this is the right place to put it, multiple different places need this...</remarks>
bool IsInInputOrMemoryCallback { get; set; }
LuaFunctionList RegisteredFunctions { get; }
public PathEntryCollection PathEntries { get; }

View File

@ -31,12 +31,14 @@ namespace BizHawk.Client.Common
private readonly LuaFunction _function;
public NamedLuaFunction(LuaFunction function, string theEvent, Action<string> logCallback, LuaFile luaFile, Func<LuaThread> createThreadCallback, string name = null)
public NamedLuaFunction(LuaFunction function, string theEvent, Action<string> logCallback, LuaFile luaFile,
Func<LuaThread> createThreadCallback, ILuaLibraries luaLibraries, string name = null)
{
_function = function;
Name = name ?? "Anonymous";
Event = theEvent;
CreateThreadCallback = createThreadCallback;
LuaLibraries = luaLibraries;
// When would a file be null?
// When a script is loaded with a callback, but no infinite loop so it closes
@ -66,8 +68,30 @@ namespace BizHawk.Client.Common
logCallback($"error running function attached by the event {Event}\nError message: {ex.Message}");
}
};
InputCallback = () => Callback(Array.Empty<object>());
MemCallback = (addr, val, flags) => Callback(new object[] { addr, val, flags });
InputCallback = () =>
{
LuaLibraries.IsInInputOrMemoryCallback = true;
try
{
Callback(Array.Empty<object>());
}
finally
{
LuaLibraries.IsInInputOrMemoryCallback = false;
}
};
MemCallback = (addr, val, flags) =>
{
LuaLibraries.IsInInputOrMemoryCallback = true;
try
{
Callback(new object[] { addr, val, flags });
}
finally
{
LuaLibraries.IsInInputOrMemoryCallback = false;
}
};
}
public void DetachFromScript()
@ -87,6 +111,11 @@ namespace BizHawk.Client.Common
public LuaFile LuaFile { get; private set; }
/// <summary>
/// HACK
/// </summary>
private ILuaLibraries LuaLibraries { get; }
private Func<LuaThread> CreateThreadCallback { get; }
public string Event { get; }

View File

@ -139,6 +139,11 @@ namespace BizHawk.Client.EmuHawk
{
if (Engaged())
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("tastudio.setplayback() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsUpdateSupressed = true;
int f;
@ -298,6 +303,11 @@ namespace BizHawk.Client.EmuHawk
{
if (Engaged())
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("tastudio.applyinputchanges() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsUpdateSupressed = true;
if (_changeList.Count > 0)
@ -424,6 +434,11 @@ namespace BizHawk.Client.EmuHawk
{
if (Engaged())
{
if (_luaLibsImpl.IsInInputOrMemoryCallback)
{
throw new InvalidOperationException("tastudio.loadbranch() is not allowed during input/memory callbacks");
}
_luaLibsImpl.IsUpdateSupressed = true;
Tastudio.LoadBranchByIndex(index);

View File

@ -165,6 +165,8 @@ namespace BizHawk.Client.EmuHawk
public bool IsUpdateSupressed { get; set; }
public bool IsInInputOrMemoryCallback { get; set; }
private readonly IDictionary<Type, LuaLibraryBase> Libraries = new Dictionary<Type, LuaLibraryBase>();
private EventWaitHandle LuaWait;
@ -309,7 +311,7 @@ namespace BizHawk.Client.EmuHawk
LuaFile luaFile,
string name = null)
{
var nlf = new NamedLuaFunction(function, theEvent, logCallback, luaFile, () => _lua.NewThread(), name);
var nlf = new NamedLuaFunction(function, theEvent, logCallback, luaFile, () => _lua.NewThread(), this, name);
RegisteredFunctions.Add(nlf);
return nlf;
}