Fix random crashes with rcheevos. The issue was that rc_runtime_t can store pointers to itself, which is bad when rcheevos expected the user to allocate that struct and did not provide functions for that. I've added that functionality and PR'd it (I'll fixup submodule to point to upstream when it's merged)
PR can be found here: https://github.com/RetroAchievements/rcheevos/pull/239 Also minor fixes wrt the ContinueWith usage in InternalDoRequest
This commit is contained in:
parent
76c8b33f16
commit
5f6d70ac46
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit c5304a61bcf256ae80fcd1c8f64ad9646aaea757
|
||||
Subproject commit b91d539638f08c7810094e9ed8aafffd72a7af26
|
|
@ -79,22 +79,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
RC_ACHIEVEMENT_CATEGORY_UNOFFICIAL = 5,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct rc_runtime_t
|
||||
{
|
||||
public IntPtr triggers;
|
||||
public int trigger_count;
|
||||
public int trigger_capacity;
|
||||
public IntPtr lboards;
|
||||
public int lboard_count;
|
||||
public int lboard_capacity;
|
||||
public IntPtr richpresence;
|
||||
public IntPtr memrefs;
|
||||
public IntPtr next_memref;
|
||||
public IntPtr variables;
|
||||
public IntPtr next_variable;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct rc_runtime_event_t
|
||||
{
|
||||
|
@ -538,65 +522,68 @@ namespace BizHawk.Client.EmuHawk
|
|||
public abstract IntPtr rc_error_str(rc_error_t error_code);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_init(ref rc_runtime_t runtime);
|
||||
public abstract IntPtr rc_runtime_alloc();
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_destroy(ref rc_runtime_t runtime);
|
||||
public abstract void rc_runtime_init(IntPtr runtime);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_reset(ref rc_runtime_t runtime);
|
||||
public abstract void rc_runtime_destroy(IntPtr runtime);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_do_frame(ref rc_runtime_t runtime, rc_runtime_event_handler_t rc_runtime_event_handler_t, rc_peek_t peek, IntPtr ud, IntPtr unused);
|
||||
public abstract void rc_runtime_reset(IntPtr runtime);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract rc_error_t rc_runtime_progress_size(ref rc_runtime_t runtime, IntPtr unused);
|
||||
public abstract void rc_runtime_do_frame(IntPtr runtime, rc_runtime_event_handler_t rc_runtime_event_handler_t, rc_peek_t peek, IntPtr ud, IntPtr unused);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_serialize_progress(byte[] buffer, ref rc_runtime_t runtime, IntPtr unused);
|
||||
public abstract rc_error_t rc_runtime_progress_size(IntPtr runtime, IntPtr unused);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract rc_error_t rc_runtime_deserialize_progress(ref rc_runtime_t runtime, byte[] serialized, IntPtr unused);
|
||||
public abstract void rc_runtime_serialize_progress(byte[] buffer, IntPtr runtime, IntPtr unused);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_invalidate_address(ref rc_runtime_t runtime, int address);
|
||||
public abstract rc_error_t rc_runtime_deserialize_progress(IntPtr runtime, byte[] serialized, IntPtr unused);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_validate_addresses(ref rc_runtime_t runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
||||
public abstract void rc_runtime_invalidate_address(IntPtr runtime, int address);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract rc_error_t rc_runtime_activate_achievement(ref rc_runtime_t runtime, int id, string memaddr, IntPtr unused, int unused_idx);
|
||||
public abstract void rc_runtime_validate_addresses(IntPtr runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract rc_error_t rc_runtime_activate_lboard(ref rc_runtime_t runtime, int id, string memaddr, IntPtr unused, int unused_idx);
|
||||
public abstract rc_error_t rc_runtime_activate_achievement(IntPtr runtime, int id, string memaddr, IntPtr unused, int unused_idx);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract rc_error_t rc_runtime_activate_richpresence(ref rc_runtime_t runtime, string script, IntPtr unused, int unused_idx);
|
||||
public abstract rc_error_t rc_runtime_activate_lboard(IntPtr runtime, int id, string memaddr, IntPtr unused, int unused_idx);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract IntPtr rc_runtime_get_achievement(ref rc_runtime_t runtime, int id);
|
||||
public abstract rc_error_t rc_runtime_activate_richpresence(IntPtr runtime, string script, IntPtr unused, int unused_idx);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract IntPtr rc_runtime_get_lboard(ref rc_runtime_t runtime, int id);
|
||||
public abstract IntPtr rc_runtime_get_achievement(IntPtr runtime, int id);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract int rc_runtime_get_richpresence(ref rc_runtime_t runtime, byte[] buffer, int buffersize, rc_peek_t peek, IntPtr ud, IntPtr unused);
|
||||
public abstract IntPtr rc_runtime_get_lboard(IntPtr runtime, int id);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract int rc_runtime_get_richpresence(IntPtr runtime, byte[] buffer, int buffersize, rc_peek_t peek, IntPtr ud, IntPtr unused);
|
||||
|
||||
[BizImport(cc)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public abstract bool rc_runtime_get_achievement_measured(ref rc_runtime_t runtime, int id, out int measured_value, out int measured_target);
|
||||
public abstract bool rc_runtime_get_achievement_measured(IntPtr runtime, int id, out int measured_value, out int measured_target);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract int rc_runtime_format_achievement_measured(ref rc_runtime_t runtime, int id, byte[] buffer, long buffer_size);
|
||||
public abstract int rc_runtime_format_achievement_measured(IntPtr runtime, int id, byte[] buffer, long buffer_size);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract int rc_runtime_format_lboard_value(byte[] buffer, int size, int value, int format);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_deactivate_achievement(ref rc_runtime_t runtime, int id);
|
||||
public abstract void rc_runtime_deactivate_achievement(IntPtr runtime, int id);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_runtime_deactivate_lboard(ref rc_runtime_t runtime, int id);
|
||||
public abstract void rc_runtime_deactivate_lboard(IntPtr runtime, int id);
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void rc_hash_init_error_message_callback(rc_hash_message_callback callback);
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private string GetCheevoProgress(int id)
|
||||
{
|
||||
var len = _lib.rc_runtime_format_achievement_measured(ref _runtime, id, _cheevoFormatBuffer, _cheevoFormatBuffer.Length);
|
||||
var len = _lib.rc_runtime_format_achievement_measured(_runtime, id, _cheevoFormatBuffer, _cheevoFormatBuffer.Length);
|
||||
return Encoding.ASCII.GetString(_cheevoFormatBuffer, 0, len);
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (cheevo.IsEnabled && !cheevo.IsUnlocked(hardcore))
|
||||
{
|
||||
_lib.rc_runtime_deactivate_achievement(ref _runtime, cheevo.ID);
|
||||
_lib.rc_runtime_deactivate_achievement(_runtime, cheevo.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (cheevo.IsEnabled && !cheevo.IsUnlocked(hardcore))
|
||||
{
|
||||
_lib.rc_runtime_activate_achievement(ref _runtime, cheevo.ID, cheevo.Definition, IntPtr.Zero, 0);
|
||||
_lib.rc_runtime_activate_achievement(_runtime, cheevo.ID, cheevo.Definition, IntPtr.Zero, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void OneShotActivateActiveModeCheevos()
|
||||
{
|
||||
if (_activeModeCheevosOnceActivated) return;
|
||||
if (_activeModeCheevosOnceActivated || _gameData.GameID == 0) return;
|
||||
_activeModeUnlocksRequest.Wait();
|
||||
ActivateCheevos(HardcoreMode);
|
||||
}
|
||||
|
|
|
@ -307,12 +307,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
foreach (var lboard in _gameData.LBoardEnumerable)
|
||||
{
|
||||
_lib.rc_runtime_activate_lboard(ref _runtime, lboard.ID, lboard.Definition, IntPtr.Zero, 0);
|
||||
_lib.rc_runtime_activate_lboard(_runtime, lboard.ID, lboard.Definition, IntPtr.Zero, 0);
|
||||
}
|
||||
|
||||
if (_gameData.RichPresenseScript is not null)
|
||||
{
|
||||
_lib.rc_runtime_activate_richpresence(ref _runtime, _gameData.RichPresenseScript, IntPtr.Zero, 0);
|
||||
_lib.rc_runtime_activate_richpresence(_runtime, _gameData.RichPresenseScript, IntPtr.Zero, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
var apiTask = request.post_data != IntPtr.Zero
|
||||
? HttpPost(request.URL, request.PostData)
|
||||
: HttpGet(request.URL);
|
||||
apiTask.ConfigureAwait(false);
|
||||
|
||||
apiTask.ContinueWith(async t =>
|
||||
{
|
||||
|
@ -126,7 +125,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
ShouldRetry = false; // this is a bit naive, but if the response callback "fails," retrying will just result in the same thing
|
||||
_completionEvent.Set();
|
||||
}
|
||||
});
|
||||
}, default, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default);
|
||||
|
||||
_lib.rc_api_destroy_request(ref request);
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (RichPresenceActive)
|
||||
{
|
||||
var len = _lib.rc_runtime_get_richpresence(ref _runtime, _richPresenceBuffer, _richPresenceBuffer.Length, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
var len = _lib.rc_runtime_get_richpresence(_runtime, _richPresenceBuffer, _richPresenceBuffer.Length, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
CurrentRichPresence = Encoding.UTF8.GetString(_richPresenceBuffer, 0, len);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_lib = BizInvoker.GetInvoker<LibRCheevos>(resolver, CallingConventionAdapters.Native);
|
||||
}
|
||||
|
||||
private LibRCheevos.rc_runtime_t _runtime;
|
||||
private IntPtr _runtime;
|
||||
|
||||
private readonly LibRCheevos.rc_runtime_event_handler_t _eventcb;
|
||||
private readonly LibRCheevos.rc_peek_t _peekcb;
|
||||
|
@ -200,8 +200,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
_httpThread = new(HttpRequestThreadProc) { IsBackground = true, Priority = ThreadPriority.BelowNormal };
|
||||
_httpThread.Start();
|
||||
|
||||
_runtime = default;
|
||||
_lib.rc_runtime_init(ref _runtime);
|
||||
_runtime = _lib.rc_runtime_alloc();
|
||||
if (_runtime == IntPtr.Zero)
|
||||
{
|
||||
throw new("rc_runtime_alloc returned NULL!");
|
||||
}
|
||||
Login();
|
||||
|
||||
_eventcb = EventHandlerCallback;
|
||||
|
@ -228,7 +231,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
_isActive = false;
|
||||
_httpThread.Join();
|
||||
|
||||
_lib.rc_runtime_destroy(ref _runtime);
|
||||
_lib.rc_runtime_destroy(_runtime);
|
||||
_runtime = IntPtr.Zero;
|
||||
Stop();
|
||||
_gameInfoForm.Dispose();
|
||||
_cheevoListForm.Dispose();
|
||||
|
@ -247,11 +251,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
OneShotActivateActiveModeCheevos();
|
||||
|
||||
var size = _lib.rc_runtime_progress_size(ref _runtime, IntPtr.Zero);
|
||||
var size = _lib.rc_runtime_progress_size(_runtime, IntPtr.Zero);
|
||||
if (size > 0)
|
||||
{
|
||||
var buffer = new byte[(int)size];
|
||||
_lib.rc_runtime_serialize_progress(buffer, ref _runtime, IntPtr.Zero);
|
||||
_lib.rc_runtime_serialize_progress(buffer, _runtime, IntPtr.Zero);
|
||||
using var file = File.OpenWrite(path + ".rap");
|
||||
file.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
@ -271,13 +275,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
OneShotActivateActiveModeCheevos();
|
||||
|
||||
_lib.rc_runtime_reset(ref _runtime);
|
||||
_lib.rc_runtime_reset(_runtime);
|
||||
|
||||
if (!File.Exists(path + ".rap")) return;
|
||||
|
||||
using var file = File.OpenRead(path + ".rap");
|
||||
var buffer = file.ReadAllBytes();
|
||||
_lib.rc_runtime_deserialize_progress(ref _runtime, buffer, IntPtr.Zero);
|
||||
_lib.rc_runtime_deserialize_progress(_runtime, buffer, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void QuickLoadCallback(object _, BeforeQuickLoadEventArgs e)
|
||||
|
@ -326,9 +330,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
// reinit the runtime
|
||||
_lib.rc_runtime_destroy(ref _runtime);
|
||||
_runtime = default;
|
||||
_lib.rc_runtime_init(ref _runtime);
|
||||
_lib.rc_runtime_destroy(_runtime);
|
||||
_runtime = _lib.rc_runtime_alloc();
|
||||
if (_runtime == IntPtr.Zero)
|
||||
{
|
||||
throw new("rc_runtime_alloc returned NULL!");
|
||||
}
|
||||
|
||||
// get console id
|
||||
_consoleId = SystemIdToConsoleId();
|
||||
|
@ -399,7 +406,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
// validate addresses now that we have cheevos init
|
||||
// ReSharper disable once ConvertToLocalFunction
|
||||
LibRCheevos.rc_runtime_validate_address_t peekcb = address => _readMap.ContainsKey(address);
|
||||
_lib.rc_runtime_validate_addresses(ref _runtime, _eventcb, peekcb);
|
||||
_lib.rc_runtime_validate_addresses(_runtime, _eventcb, peekcb);
|
||||
|
||||
_gameInfoForm.Restart(_gameData.Title, _gameData.TotalCheevoPoints(HardcoreMode), CurrentRichPresence ?? "N/A");
|
||||
_cheevoListForm.Restart(_gameData.GameID == 0 ? Array.Empty<Cheevo>() : _gameData.CheevoEnumerable, GetCheevoProgress);
|
||||
|
@ -443,7 +450,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
var cheevo = _gameData.GetCheevoById(evt->id);
|
||||
if (cheevo.IsEnabled)
|
||||
{
|
||||
_lib.rc_runtime_deactivate_achievement(ref _runtime, evt->id);
|
||||
_lib.rc_runtime_deactivate_achievement(_runtime, evt->id);
|
||||
|
||||
cheevo.SetUnlocked(HardcoreMode, true);
|
||||
var prefix = HardcoreMode ? "[HARDCORE] " : "";
|
||||
|
@ -610,7 +617,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
var input = _inputManager.ControllerOutput;
|
||||
if (input.Definition.BoolButtons.Any(b => (b.Contains("Power") || b.Contains("Reset")) && input.IsPressed(b)))
|
||||
{
|
||||
_lib.rc_runtime_reset(ref _runtime);
|
||||
_lib.rc_runtime_reset(_runtime);
|
||||
}
|
||||
|
||||
if (Emu.HasMemoryDomains())
|
||||
|
@ -618,12 +625,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
// we want to EnterExit to prevent wbx host spam when peeks are spammed
|
||||
using (Domains.MainMemory.EnterExit())
|
||||
{
|
||||
_lib.rc_runtime_do_frame(ref _runtime, _eventcb, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
_lib.rc_runtime_do_frame(_runtime, _eventcb, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_lib.rc_runtime_do_frame(ref _runtime, _eventcb, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
_lib.rc_runtime_do_frame(_runtime, _eventcb, _peekcb, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (_gameInfoForm.IsShown)
|
||||
|
|
Loading…
Reference in New Issue