do cleanup with rcheevos, using record structs where possible

also add in `in` support for the BizInvoker for compat interop
(non-compat interop doesn't really matter here, the point of `in` is to avoid a copy back for non-blittable objects, which doesn't apply for non-compat which only works for blittable objects / always just pins them down)
This commit is contained in:
CasualPokePlayer 2023-12-10 15:58:04 -08:00
parent 83e784ecec
commit 6b0b6f2106
12 changed files with 169 additions and 532 deletions

View File

@ -2,6 +2,7 @@
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace BizHawk.BizInvoke
@ -83,7 +84,7 @@ namespace BizHawk.BizInvoke
// anything more clever we can do here?
var t = o.GetType();
if (t == typeof(OutAttribute) || t == typeof(InAttribute))
if (t == typeof(OutAttribute) || t == typeof(InAttribute) || t == typeof(IsReadOnlyAttribute))
{
return new(t.GetConstructor(Type.EmptyTypes)!, Array.Empty<object>());
}

View File

@ -223,6 +223,18 @@ namespace BizHawk.BizInvoke
var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
var returnType = baseMethod.ReturnType;
static Type[]? NullifyIfEmpty(Type[]? t)
=> t?.Length == 0 ? null : t;
static Type[]?[]? NullifyIfAllNull(Type[]?[] t)
=> t.All(t => t == null) ? null : t;
// this stuff is required for in
var paramTypeRequiredCustomModifiers = NullifyIfAllNull(paramInfos.Select(pi => NullifyIfEmpty(pi.GetRequiredCustomModifiers())).ToArray());
var paramTypeOptionalCustomModifiers = NullifyIfAllNull(paramInfos.Select(pi => NullifyIfEmpty(pi.GetOptionalCustomModifiers())).ToArray());
var returnTypeRequiredCustomModifiers = NullifyIfEmpty(baseMethod.ReturnParameter?.GetRequiredCustomModifiers());
var returnTypeOptionalCustomModifiers = NullifyIfEmpty(baseMethod.ReturnParameter?.GetRequiredCustomModifiers());
if (paramTypes.Concat(new[] { returnType }).Any(typeof(Delegate).IsAssignableFrom))
{
// this isn't a problem if CallingConventionAdapters.Waterbox is a no-op, but it is otherwise: we don't
@ -245,7 +257,11 @@ namespace BizHawk.BizInvoke
MethodAttributes.Virtual | MethodAttributes.Public,
CallingConventions.HasThis,
returnType,
paramTypes);
returnTypeRequiredCustomModifiers,
returnTypeOptionalCustomModifiers,
paramTypes,
paramTypeRequiredCustomModifiers,
paramTypeOptionalCustomModifiers);
var il = method.GetILGenerator();

View File

@ -5,13 +5,13 @@ using System.Runtime.InteropServices;
using BizHawk.BizInvoke;
using BizHawk.Common;
#pragma warning disable IDE1006 // Naming Styles
// ReSharper disable UnusedMember.Global
// ReSharper disable EnumUnderlyingTypeIsInt
// not sure about these wrt marshalling, so ignore for now
// ReSharper disable FieldCanBeMadeReadOnly.Global
// time_t = long?
// TODO: Make these record structs
#pragma warning disable IDE1006 // Naming Styles
// ReSharper disable NotAccessedPositionalProperty.Global
// ReSharper disable StructCanBeMadeReadOnly
// ReSharper disable UnusedMember.Global
namespace BizHawk.Client.EmuHawk
{
@ -99,13 +99,7 @@ namespace BizHawk.Client.EmuHawk
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_buffer_chunk_t
{
public IntPtr write;
public IntPtr end;
public IntPtr start;
public IntPtr next;
}
public record struct rc_buffer_chunk_t(IntPtr write, IntPtr end, IntPtr start, IntPtr next);
[StructLayout(LayoutKind.Sequential)]
public struct rc_buffer_t
@ -115,468 +109,191 @@ namespace BizHawk.Client.EmuHawk
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_request_t
public record struct rc_api_request_t(IntPtr url, IntPtr post_data, IntPtr content_type, rc_buffer_t buffer)
{
public IntPtr url;
public IntPtr post_data;
public IntPtr content_type;
public rc_buffer_t buffer;
public string URL => Mershul.PtrToStringUtf8(url);
public string PostData => Mershul.PtrToStringUtf8(post_data);
public string ContentType => Mershul.PtrToStringUtf8(content_type);
public readonly string URL => Mershul.PtrToStringUtf8(url);
public readonly string PostData => Mershul.PtrToStringUtf8(post_data);
public readonly string ContentType => Mershul.PtrToStringUtf8(content_type);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_response_t
public record struct rc_api_response_t(int succeeded, IntPtr error_message, IntPtr error_code, rc_buffer_t buffer)
{
public int succeeded;
public IntPtr error_message;
public IntPtr error_code;
public rc_buffer_t buffer;
public readonly string ErrorMessage => Mershul.PtrToStringUtf8(error_message);
public readonly string ErrorCode => Mershul.PtrToStringUtf8(error_code);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_user_unlocks_response_t
{
public unsafe uint* achievement_ids;
public uint num_achievement_ids;
public rc_api_response_t response;
}
public record struct rc_api_fetch_user_unlocks_response_t(IntPtr achievement_ids, uint num_achievement_ids, rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_login_response_t
public record struct rc_api_login_response_t(
IntPtr username, IntPtr api_token, uint score, uint score_softcore, uint num_unread_messages, IntPtr display_name, rc_api_response_t response)
{
public IntPtr username;
public IntPtr api_token;
public uint score;
public uint score_softcore;
public uint num_unread_messages;
public IntPtr display_name;
public rc_api_response_t response;
public readonly string Username => Mershul.PtrToStringUtf8(username);
public readonly string ApiToken => Mershul.PtrToStringUtf8(api_token);
public readonly string DisplayName => Mershul.PtrToStringUtf8(display_name);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_unlock_entry_t
{
public uint achievement_id;
public long when; // time_t?
}
public record struct rc_api_start_session_response_t(
IntPtr hardcore_unlocks, IntPtr unlocks, uint num_hardcore_unlocks, uint num_unlocks, long server_now, rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_start_session_response_t
{
public unsafe rc_api_unlock_entry_t* hardcore_unlocks;
public unsafe rc_api_unlock_entry_t* unlocks;
public uint num_hardcore_unlocks;
public uint num_unlocks;
public long server_now; // time_t?
public rc_api_response_t response;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_user_unlocks_request_t
public readonly record struct rc_api_fetch_user_unlocks_request_t(string username, string api_token, uint game_id, bool hardcore)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint game_id;
public readonly string api_token = api_token;
public readonly uint game_id = game_id;
[MarshalAs(UnmanagedType.Bool)]
public bool hardcore;
public rc_api_fetch_user_unlocks_request_t(string username, string api_token, uint game_id, bool hardcore)
{
this.username = username;
this.api_token = api_token;
this.game_id = game_id;
this.hardcore = hardcore;
}
public readonly bool hardcore = hardcore;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_login_request_t
public readonly record struct rc_api_login_request_t(string username, string api_token, string password)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public readonly string api_token = api_token;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string password;
public rc_api_login_request_t(string username, string api_token, string password)
{
this.username = username;
this.api_token = api_token;
this.password = password;
}
public readonly string password = password;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_start_session_request_t
public readonly record struct rc_api_start_session_request_t(string username, string api_token, uint game_id)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint game_id;
public rc_api_start_session_request_t(string username, string api_token, uint game_id)
{
this.username = username;
this.api_token = api_token;
this.game_id = game_id;
}
public readonly string api_token = api_token;
public readonly uint game_id = game_id;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_award_achievement_response_t
public record struct rc_api_award_achievement_response_t(
uint awarded_achievement_id,
uint new_player_score,
uint new_player_score_softcore,
uint achievements_remaining,
rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public readonly record struct rc_api_achievement_definition_t(uint id, uint points, rc_runtime_achievement_category_t category,
IntPtr title, IntPtr description, IntPtr definition, IntPtr author, IntPtr badge_name, long created, long updated)
{
public uint awarded_achievement_id;
public uint new_player_score;
public uint new_player_score_softcore;
public uint achievements_remaining;
public rc_api_response_t response;
public string Title => Mershul.PtrToStringUtf8(title);
public string Description => Mershul.PtrToStringUtf8(description);
public string Definition => Mershul.PtrToStringUtf8(definition);
public string Author => Mershul.PtrToStringUtf8(author);
public string BadgeName => Mershul.PtrToStringUtf8(badge_name);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_achievement_definition_t
public readonly record struct rc_api_leaderboard_definition_t(
uint id, int format, IntPtr title, IntPtr description, IntPtr definition, byte lower_is_better, byte hidden)
{
public uint id;
public uint points;
public rc_runtime_achievement_category_t category;
public IntPtr title;
public IntPtr description;
public IntPtr definition;
public IntPtr author;
public IntPtr badge_name;
public long created; // time_t?
public long updated; // time_t?
public readonly string Title => Mershul.PtrToStringUtf8(title);
public readonly string Description => Mershul.PtrToStringUtf8(description);
public readonly string Definition => Mershul.PtrToStringUtf8(definition);
public readonly string Author => Mershul.PtrToStringUtf8(author);
public readonly string BadgeName => Mershul.PtrToStringUtf8(badge_name);
public string Title => Mershul.PtrToStringUtf8(title);
public string Description => Mershul.PtrToStringUtf8(description);
public string Definition => Mershul.PtrToStringUtf8(definition);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_leaderboard_definition_t
public record struct rc_api_fetch_game_data_response_t(uint id, RetroAchievements.ConsoleID console_id, IntPtr title, IntPtr image_name,
IntPtr rich_presence_script, IntPtr achievements, uint num_achievements, IntPtr leaderboards, uint num_leaderboards, rc_api_response_t response)
{
public uint id;
public int format;
public IntPtr title;
public IntPtr description;
public IntPtr definition;
public byte lower_is_better;
public byte hidden;
public readonly string Title => Mershul.PtrToStringUtf8(title);
public readonly string Description => Mershul.PtrToStringUtf8(description);
public readonly string Definition => Mershul.PtrToStringUtf8(definition);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_game_data_response_t
{
public uint id;
public RetroAchievements.ConsoleID console_id;
public IntPtr title;
public IntPtr image_name;
public IntPtr rich_presence_script;
public unsafe rc_api_achievement_definition_t* achievements;
public uint num_achievements;
public unsafe rc_api_leaderboard_definition_t* leaderboards;
public uint num_leaderboards;
public rc_api_response_t response;
public readonly string Title => Mershul.PtrToStringUtf8(title);
public readonly string ImageName => Mershul.PtrToStringUtf8(image_name);
public readonly string RichPresenceScript => Mershul.PtrToStringUtf8(rich_presence_script);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_ping_response_t
{
public rc_api_response_t response;
}
public record struct rc_api_ping_response_t(rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_resolve_hash_response_t
{
public uint game_id;
public rc_api_response_t response;
}
public record struct rc_api_resolve_hash_response_t(uint game_id, rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_lboard_entry_t
{
public IntPtr username;
public uint rank;
public int score;
public readonly string Username => Mershul.PtrToStringUtf8(username);
}
public record struct rc_api_submit_lboard_entry_response_t(
int submitted_score, int best_score, uint new_rank, uint num_entries, IntPtr top_entries, uint num_top_entries, rc_api_response_t response);
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_submit_lboard_entry_response_t
{
public int submitted_score;
public int best_score;
public uint new_rank;
public uint num_entries;
public unsafe rc_api_lboard_entry_t* top_entries;
public uint num_top_entries;
public rc_api_response_t response;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_award_achievement_request_t
public readonly record struct rc_api_award_achievement_request_t(string username, string api_token, uint achievement_id, bool hardcore, string game_hash)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint achievement_id;
public readonly string api_token = api_token;
public readonly uint achievement_id = achievement_id;
[MarshalAs(UnmanagedType.Bool)]
public bool hardcore;
public readonly bool hardcore = hardcore;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string game_hash;
public rc_api_award_achievement_request_t(string username, string api_token, uint achievement_id, bool hardcore, string game_hash)
{
this.username = username;
this.api_token = api_token;
this.achievement_id = achievement_id;
this.hardcore = hardcore;
this.game_hash = game_hash;
}
public readonly string game_hash = game_hash;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_game_data_request_t
public readonly record struct rc_api_fetch_game_data_request_t(string username, string api_token, uint game_id)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint game_id;
public rc_api_fetch_game_data_request_t(string username, string api_token, uint game_id)
{
this.username = username;
this.api_token = api_token;
this.game_id = game_id;
}
public readonly string api_token = api_token;
public readonly uint game_id = game_id;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_image_request_t
public readonly record struct rc_api_fetch_image_request_t(string image_name, rc_api_image_type_t image_type)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string image_name;
public rc_api_image_type_t image_type;
public rc_api_fetch_image_request_t(string image_name, rc_api_image_type_t image_type)
{
this.image_name = image_name;
this.image_type = image_type;
}
public readonly string image_name = image_name;
public readonly rc_api_image_type_t image_type = image_type;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_ping_request_t
public readonly record struct rc_api_ping_request_t(string username, string api_token, uint game_id, string rich_presence)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint game_id;
public readonly string api_token = api_token;
public readonly uint game_id = game_id;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string rich_presence;
public rc_api_ping_request_t(string username, string api_token, uint game_id, string rich_presence)
{
this.username = username;
this.api_token = api_token;
this.game_id = game_id;
this.rich_presence = rich_presence;
}
public readonly string rich_presence = rich_presence;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_resolve_hash_request_t
public readonly record struct rc_api_resolve_hash_request_t(string username, string api_token, string game_hash)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username; // note: not actually used
public readonly string username = username; // note: not actually used
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token; // note: not actually used
public readonly string api_token = api_token; // note: not actually used
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string game_hash;
public rc_api_resolve_hash_request_t(string username, string api_token, string game_hash)
{
this.username = username;
this.api_token = api_token;
this.game_hash = game_hash;
}
public readonly string game_hash = game_hash;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_submit_lboard_entry_request_t
public readonly record struct rc_api_submit_lboard_entry_request_t(string username, string api_token, uint leaderboard_id, int score, string game_hash)
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public readonly string username = username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint leaderboard_id;
public int score;
public readonly string api_token = api_token;
public readonly uint leaderboard_id = leaderboard_id;
public readonly int score = score;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string game_hash;
public rc_api_submit_lboard_entry_request_t(string username, string api_token, uint leaderboard_id, int score, string game_hash)
{
this.username = username;
this.api_token = api_token;
this.leaderboard_id = leaderboard_id;
this.score = score;
this.game_hash = game_hash;
}
public readonly string game_hash = game_hash;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_achievement_awarded_entry_t
{
public IntPtr username;
public long awarded; // time_t?
public string Username => Mershul.PtrToStringUtf8(username);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_achievement_info_response_t
{
public uint id;
public uint game_id;
public uint num_awarded;
public uint num_players;
public unsafe rc_api_achievement_awarded_entry_t* recently_awarded;
public uint num_recently_awarded;
public rc_api_response_t response;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_game_list_entry_t
{
public uint id;
public IntPtr name;
public readonly string Name => Mershul.PtrToStringUtf8(name);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_games_list_response_t
{
public unsafe rc_api_game_list_entry_t* entries;
public uint num_entries;
public rc_api_response_t response;
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_lboard_info_entry_t
{
public IntPtr username;
public uint rank;
public uint index;
public int score;
public long submitted; // time_t?
public readonly string Username => Mershul.PtrToStringUtf8(username);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_leaderboard_info_response_t
{
public uint id;
public int format;
public uint lower_is_better;
public IntPtr title;
public IntPtr description;
public IntPtr definition;
public uint game_id;
public IntPtr author;
public long created; // time_t?
public long updated; // time_t?
public unsafe rc_api_lboard_info_entry_t* entries;
public uint num_entries;
public rc_api_response_t response;
public readonly string Title => Mershul.PtrToStringUtf8(title);
public readonly string Description => Mershul.PtrToStringUtf8(description);
public readonly string Definition => Mershul.PtrToStringUtf8(definition);
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_achievement_info_request_t
{
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string api_token;
public uint achievement_id;
public uint first_entry;
public uint count;
public uint friends_only;
public rc_api_fetch_achievement_info_request_t(string username, string api_token, uint achievement_id, uint first_entry, uint count, uint friends_only)
{
this.username = username;
this.api_token = api_token;
this.achievement_id = achievement_id;
this.first_entry = first_entry;
this.count = count;
this.friends_only = friends_only;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_games_list_request_t
{
public uint console_id;
public rc_api_fetch_games_list_request_t(uint console_id)
{
this.console_id = console_id;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_api_fetch_leaderboard_info_request_t
{
public uint leaderboard_id;
public uint count;
public uint first_entry;
[MarshalAs(UnmanagedType.LPUTF8Str)]
public string username;
public rc_api_fetch_leaderboard_info_request_t(uint leaderboard_id, uint count, uint first_entry, string username)
{
this.leaderboard_id = leaderboard_id;
this.count = count;
this.first_entry = first_entry;
this.username = username;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_hash_filereader
public readonly record struct rc_hash_filereader(
rc_hash_filereader.rc_hash_filereader_open_file_handler open,
rc_hash_filereader.rc_hash_filereader_seek_handler seek,
rc_hash_filereader.rc_hash_filereader_tell_handler tell,
rc_hash_filereader.rc_hash_filereader_read_handler read,
rc_hash_filereader.rc_hash_filereader_close_file_handler close)
{
[UnmanagedFunctionPointer(cc)]
public delegate IntPtr rc_hash_filereader_open_file_handler([MarshalAs(UnmanagedType.LPUTF8Str)] string path_utf8);
@ -588,63 +305,30 @@ namespace BizHawk.Client.EmuHawk
public delegate long rc_hash_filereader_tell_handler(IntPtr file_handle);
[UnmanagedFunctionPointer(cc)]
public delegate UIntPtr rc_hash_filereader_read_handler(IntPtr file_handle, IntPtr buffer, UIntPtr requested_bytes);
public delegate nuint rc_hash_filereader_read_handler(IntPtr file_handle, IntPtr buffer, nuint requested_bytes);
[UnmanagedFunctionPointer(cc)]
public delegate void rc_hash_filereader_close_file_handler(IntPtr file_handle);
public rc_hash_filereader_open_file_handler open;
public rc_hash_filereader_seek_handler seek;
public rc_hash_filereader_tell_handler tell;
public rc_hash_filereader_read_handler read;
public rc_hash_filereader_close_file_handler close;
public rc_hash_filereader(
rc_hash_filereader_open_file_handler open,
rc_hash_filereader_seek_handler seek,
rc_hash_filereader_tell_handler tell,
rc_hash_filereader_read_handler read,
rc_hash_filereader_close_file_handler close)
{
this.open = open;
this.seek = seek;
this.tell = tell;
this.read = read;
this.close = close;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct rc_hash_cdreader
public readonly record struct rc_hash_cdreader(
rc_hash_cdreader.rc_hash_cdreader_open_track_handler open_track,
rc_hash_cdreader.rc_hash_cdreader_read_sector_handler read_sector,
rc_hash_cdreader.rc_hash_cdreader_close_track_handler close_track,
rc_hash_cdreader.rc_hash_cdreader_first_track_sector_handler first_track_sector)
{
[UnmanagedFunctionPointer(cc)]
public delegate IntPtr rc_hash_cdreader_open_track_handler([MarshalAs(UnmanagedType.LPUTF8Str)] string path, int track);
[UnmanagedFunctionPointer(cc)]
public delegate UIntPtr rc_hash_cdreader_read_sector_handler(IntPtr track_handle, uint sector, IntPtr buffer, UIntPtr requested_bytes);
public delegate nuint rc_hash_cdreader_read_sector_handler(IntPtr track_handle, uint sector, IntPtr buffer, nuint requested_bytes);
[UnmanagedFunctionPointer(cc)]
public delegate void rc_hash_cdreader_close_track_handler(IntPtr track_handle);
[UnmanagedFunctionPointer(cc)]
public delegate uint rc_hash_cdreader_first_track_sector_handler(IntPtr track_handle);
public rc_hash_cdreader_open_track_handler open_track;
public rc_hash_cdreader_read_sector_handler read_sector;
public rc_hash_cdreader_close_track_handler close_track;
public rc_hash_cdreader_first_track_sector_handler first_track_sector;
public rc_hash_cdreader(
rc_hash_cdreader_open_track_handler open_track,
rc_hash_cdreader_read_sector_handler read_sector,
rc_hash_cdreader_close_track_handler close_track,
rc_hash_cdreader_first_track_sector_handler first_track_sector)
{
this.open_track = open_track;
this.read_sector = read_sector;
this.close_track = close_track;
this.first_track_sector = first_track_sector;
}
}
[UnmanagedFunctionPointer(cc)]
@ -658,13 +342,7 @@ namespace BizHawk.Client.EmuHawk
public delegate bool rc_runtime_validate_address_t(uint address);
[UnmanagedFunctionPointer(cc)]
public delegate void rc_hash_message_callback(string message);
[BizImport(cc)]
public abstract IntPtr rc_console_memory_regions(RetroAchievements.ConsoleID id);
[BizImport(cc)]
public abstract IntPtr rc_console_name(RetroAchievements.ConsoleID id);
public delegate void rc_hash_message_callback([MarshalAs(UnmanagedType.LPUTF8Str)] string message);
[BizImport(cc)]
public abstract IntPtr rc_error_str(rc_error_t error_code);
@ -672,9 +350,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract IntPtr rc_runtime_alloc();
[BizImport(cc)]
public abstract void rc_runtime_init(IntPtr runtime);
[BizImport(cc)]
public abstract void rc_runtime_destroy(IntPtr runtime);
@ -693,9 +368,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract rc_error_t rc_runtime_deserialize_progress(IntPtr runtime, byte[] serialized, IntPtr unused);
[BizImport(cc)]
public abstract void rc_runtime_invalidate_address(IntPtr runtime, uint address);
[BizImport(cc)]
public abstract void rc_runtime_validate_addresses(IntPtr runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
@ -709,20 +381,10 @@ namespace BizHawk.Client.EmuHawk
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_achievement(IntPtr runtime, uint id);
public abstract int rc_runtime_get_richpresence(IntPtr runtime, byte[] buffer, nuint buffersize, rc_runtime_peek_t peek, IntPtr ud, IntPtr unused);
[BizImport(cc)]
public abstract IntPtr rc_runtime_get_lboard(IntPtr runtime, uint id);
[BizImport(cc)]
public abstract int rc_runtime_get_richpresence(IntPtr runtime, byte[] buffer, UIntPtr buffersize, rc_runtime_peek_t peek, IntPtr ud, IntPtr unused);
[BizImport(cc)]
[return: MarshalAs(UnmanagedType.Bool)]
public abstract bool rc_runtime_get_achievement_measured(IntPtr runtime, uint id, out uint measured_value, out uint measured_target);
[BizImport(cc)]
public abstract int rc_runtime_format_achievement_measured(IntPtr runtime, uint id, byte[] buffer, UIntPtr buffer_size);
public abstract int rc_runtime_format_achievement_measured(IntPtr runtime, uint id, byte[] buffer, nuint buffer_size);
[BizImport(cc)]
public abstract int rc_runtime_format_lboard_value(byte[] buffer, int size, int value, int format);
@ -730,9 +392,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract void rc_runtime_deactivate_achievement(IntPtr runtime, uint id);
[BizImport(cc)]
public abstract void rc_runtime_deactivate_lboard(IntPtr runtime, uint id);
[BizImport(cc)]
public abstract void rc_hash_init_error_message_callback(rc_hash_message_callback callback);
@ -740,70 +399,45 @@ namespace BizHawk.Client.EmuHawk
public abstract void rc_hash_init_verbose_message_callback(rc_hash_message_callback callback);
[BizImport(cc, Compatibility = true)]
public abstract void rc_hash_init_custom_cdreader(ref rc_hash_cdreader reader);
public abstract void rc_hash_init_custom_cdreader(in rc_hash_cdreader reader);
[BizImport(cc, Compatibility = true)]
public abstract void rc_hash_init_custom_filereader(ref rc_hash_filereader reader);
public abstract void rc_hash_init_custom_filereader(in rc_hash_filereader reader);
[BizImport(cc)]
[return: MarshalAs(UnmanagedType.Bool)]
public abstract bool rc_hash_generate_from_buffer(byte[] hash, RetroAchievements.ConsoleID console_id, byte[] buffer, UIntPtr buffer_size);
public abstract bool rc_hash_generate_from_buffer(byte[] hash, RetroAchievements.ConsoleID console_id, byte[] buffer, nuint buffer_size);
[BizImport(cc)]
[return: MarshalAs(UnmanagedType.Bool)]
public abstract bool rc_hash_generate_from_file(byte[] hash, RetroAchievements.ConsoleID console_id, string path);
[BizImport(cc)]
public abstract void rc_hash_initialize_iterator(IntPtr iterator, string path, byte[] buffer, UIntPtr buffer_size);
[BizImport(cc)]
[return: MarshalAs(UnmanagedType.Bool)]
public abstract bool rc_hash_iterate(byte[] hash, IntPtr iterator);
[BizImport(cc)]
public abstract void rc_hash_destroy_iterator(IntPtr iterator);
[BizImport(cc)]
public abstract void rc_api_set_host(string hostname);
[BizImport(cc)]
public abstract void rc_api_set_image_host(string hostname);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_login_request(out rc_api_request_t request, in rc_api_login_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_login_request(out rc_api_request_t request, ref rc_api_login_request_t api_params);
public abstract rc_error_t rc_api_init_start_session_request(out rc_api_request_t request, in rc_api_start_session_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_start_session_request(out rc_api_request_t request, ref rc_api_start_session_request_t api_params);
public abstract rc_error_t rc_api_init_resolve_hash_request(out rc_api_request_t request, in rc_api_resolve_hash_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_resolve_hash_request(out rc_api_request_t request, ref rc_api_resolve_hash_request_t api_params);
public abstract rc_error_t rc_api_init_fetch_game_data_request(out rc_api_request_t request, in rc_api_fetch_game_data_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_game_data_request(out rc_api_request_t request, ref rc_api_fetch_game_data_request_t api_params);
public abstract rc_error_t rc_api_init_fetch_user_unlocks_request(out rc_api_request_t request, in rc_api_fetch_user_unlocks_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_user_unlocks_request(out rc_api_request_t request, ref rc_api_fetch_user_unlocks_request_t api_params);
public abstract rc_error_t rc_api_init_fetch_image_request(out rc_api_request_t request, in rc_api_fetch_image_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_achievement_info_request(out rc_api_request_t request, ref rc_api_fetch_achievement_info_request_t api_params);
public abstract rc_error_t rc_api_init_award_achievement_request(out rc_api_request_t request, in rc_api_award_achievement_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_leaderboard_info_request(out rc_api_request_t request, ref rc_api_fetch_leaderboard_info_request_t api_params);
public abstract rc_error_t rc_api_init_submit_lboard_entry_request(out rc_api_request_t request, in rc_api_submit_lboard_entry_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_image_request(out rc_api_request_t request, ref rc_api_fetch_image_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_award_achievement_request(out rc_api_request_t request, ref rc_api_award_achievement_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_submit_lboard_entry_request(out rc_api_request_t request, ref rc_api_submit_lboard_entry_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_ping_request(out rc_api_request_t request, ref rc_api_ping_request_t api_params);
[BizImport(cc, Compatibility = true)]
public abstract rc_error_t rc_api_init_fetch_games_list_request(out rc_api_request_t request, ref rc_api_fetch_games_list_request_t api_params);
public abstract rc_error_t rc_api_init_ping_request(out rc_api_request_t request, in rc_api_ping_request_t api_params);
[BizImport(cc)]
public abstract void rc_api_destroy_request(ref rc_api_request_t request);
@ -823,12 +457,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract rc_error_t rc_api_process_fetch_user_unlocks_response(out rc_api_fetch_user_unlocks_response_t response, byte[] server_response);
[BizImport(cc)]
public abstract rc_error_t rc_api_process_fetch_achievement_info_response(out rc_api_fetch_achievement_info_response_t response, byte[] server_response);
[BizImport(cc)]
public abstract rc_error_t rc_api_process_fetch_leaderboard_info_response(out rc_api_fetch_leaderboard_info_response_t response, byte[] server_response);
[BizImport(cc)]
public abstract rc_error_t rc_api_process_award_achievement_response(out rc_api_award_achievement_response_t response, byte[] server_response);
@ -838,9 +466,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract rc_error_t rc_api_process_ping_response(out rc_api_ping_response_t response, byte[] server_response);
[BizImport(cc)]
public abstract rc_error_t rc_api_process_fetch_games_list_response(out rc_api_fetch_games_list_response_t response, byte[] server_response);
[BizImport(cc)]
public abstract void rc_api_destroy_login_response(ref rc_api_login_response_t response);
@ -856,12 +481,6 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract void rc_api_destroy_fetch_user_unlocks_response(ref rc_api_fetch_user_unlocks_response_t response);
[BizImport(cc)]
public abstract void rc_api_destroy_fetch_achievement_info_response(ref rc_api_fetch_achievement_info_response_t response);
[BizImport(cc)]
public abstract void rc_api_destroy_fetch_leaderboard_info_response(ref rc_api_fetch_leaderboard_info_response_t response);
[BizImport(cc)]
public abstract void rc_api_destroy_award_achievement_response(ref rc_api_award_achievement_response_t response);
@ -870,8 +489,5 @@ namespace BizHawk.Client.EmuHawk
[BizImport(cc)]
public abstract void rc_api_destroy_ping_response(ref rc_api_ping_response_t response);
[BizImport(cc)]
public abstract void rc_api_destroy_fetch_games_list_response(ref rc_api_fetch_games_list_response_t response);
}
}

View File

@ -213,7 +213,7 @@ namespace BizHawk.Client.EmuHawk
for (var i = 0; i < _memFunctions.Count; i++)
{
_memFunctions[i].MemGuard = _memGuard;
RA.InstallMemoryBank(i, _memFunctions[i].ReadFunc, _memFunctions[i].WriteFunc, checked((int)_memFunctions[i].BankSize));
RA.InstallMemoryBank(i, _memFunctions[i].ReadFunc, _memFunctions[i].WriteFunc, (int)_memFunctions[i].BankSize);
RA.InstallMemoryBankBlockReader(i, _memFunctions[i].ReadBlockFunc);
}
}

View File

@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class CheevoUnlockRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_award_achievement_request_t _apiParams;
private readonly LibRCheevos.rc_api_award_achievement_request_t _apiParams;
protected override void ResponseCallback(byte[] serv_resp)
{
@ -25,7 +25,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_award_achievement_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_award_achievement_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -131,7 +131,7 @@ namespace BizHawk.Client.EmuHawk
private string GetCheevoProgress(uint id)
{
var len = _lib.rc_runtime_format_achievement_measured(_runtime, id, _cheevoFormatBuffer, new((uint)_cheevoFormatBuffer.Length));
var len = _lib.rc_runtime_format_achievement_measured(_runtime, id, _cheevoFormatBuffer, (uint)_cheevoFormatBuffer.Length);
return Encoding.ASCII.GetString(_cheevoFormatBuffer, 0, len);
}

View File

@ -23,7 +23,7 @@ namespace BizHawk.Client.EmuHawk
public sealed class UserUnlocksRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_fetch_user_unlocks_request_t _apiParams;
private readonly LibRCheevos.rc_api_fetch_user_unlocks_request_t _apiParams;
private readonly IReadOnlyDictionary<uint, Cheevo> _cheevos;
protected override void ResponseCallback(byte[] serv_resp)
@ -33,9 +33,10 @@ namespace BizHawk.Client.EmuHawk
{
unsafe
{
var unlocks = (uint*)resp.achievement_ids;
for (var i = 0; i < resp.num_achievement_ids; i++)
{
if (_cheevos.TryGetValue(resp.achievement_ids[i], out var cheevo))
if (_cheevos.TryGetValue(unlocks![i], out var cheevo))
{
cheevo.SetUnlocked(_apiParams.hardcore, true);
}
@ -52,7 +53,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_fetch_user_unlocks_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_fetch_user_unlocks_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -67,7 +68,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class GameDataRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_fetch_game_data_request_t _apiParams;
private readonly LibRCheevos.rc_api_fetch_game_data_request_t _apiParams;
private readonly Func<bool> _allowUnofficialCheevos;
public GameData GameData { get; private set; }
@ -90,7 +91,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
GameData = new();
var apiParamsResult = _lib.rc_api_init_fetch_game_data_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_fetch_game_data_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -103,7 +104,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class ImageRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_fetch_image_request_t _apiParams;
private readonly LibRCheevos.rc_api_fetch_image_request_t _apiParams;
public Bitmap Image { get; private set; }
@ -131,7 +132,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
var apiParamsResult = _lib.rc_api_init_fetch_image_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_fetch_image_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -195,17 +196,19 @@ namespace BizHawk.Client.EmuHawk
RichPresenseScript = resp.RichPresenceScript;
var cheevos = new Dictionary<uint, Cheevo>();
var cptr = (LibRCheevos.rc_api_achievement_definition_t*)resp.achievements;
for (var i = 0; i < resp.num_achievements; i++)
{
cheevos.Add(resp.achievements[i].id, new(in resp.achievements[i], allowUnofficialCheevos));
cheevos.Add(cptr![i].id, new(in cptr[i], allowUnofficialCheevos));
}
_cheevos = cheevos;
var lboards = new Dictionary<uint, LBoard>();
var lptr = (LibRCheevos.rc_api_leaderboard_definition_t*)resp.leaderboards;
for (var i = 0; i < resp.num_leaderboards; i++)
{
lboards.Add(resp.leaderboards[i].id, new(in resp.leaderboards[i]));
lboards.Add(lptr![i].id, new(in lptr[i]));
}
_lboards = lboards;
@ -231,7 +234,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class ResolveHashRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_resolve_hash_request_t _apiParams;
private readonly LibRCheevos.rc_api_resolve_hash_request_t _apiParams;
public uint GameID { get; private set; }
// eh? not sure I want this retried, given the blocking behavior
@ -255,7 +258,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
GameID = 0;
var apiParamsResult = _lib.rc_api_init_resolve_hash_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_resolve_hash_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -282,7 +285,7 @@ namespace BizHawk.Client.EmuHawk
protected override uint IdentifyRom(byte[] rom)
{
var hash = new byte[33];
if (_lib.rc_hash_generate_from_buffer(hash, _consoleId, rom, new((uint)rom.Length)))
if (_lib.rc_hash_generate_from_buffer(hash, _consoleId, rom, (uint)rom.Length))
{
return IdentifyHash(Encoding.ASCII.GetString(hash, 0, 32));
}

View File

@ -109,7 +109,7 @@ namespace BizHawk.Client.EmuHawk
}
var apiTask = request.post_data != IntPtr.Zero
? HttpPost(request.URL, request.PostData)
? HttpPost(request.URL, request.PostData, request.ContentType)
: HttpGet(request.URL);
apiTask.ContinueWith(async t =>
@ -243,11 +243,11 @@ namespace BizHawk.Client.EmuHawk
}
}
private static async Task<byte[]> HttpPost(string url, string post)
private static async Task<byte[]> HttpPost(string url, string post, string type)
{
try
{
using var content = new StringContent(post, Encoding.UTF8, "application/x-www-form-urlencoded");
using var content = new StringContent(post, Encoding.UTF8, type ?? "application/x-www-form-urlencoded");
using var response = await _http.PostAsync(url, content).ConfigureAwait(false);
return response.IsSuccessStatusCode
? await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false)

View File

@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class LboardTriggerRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_submit_lboard_entry_request_t _apiParams;
private readonly LibRCheevos.rc_api_submit_lboard_entry_request_t _apiParams;
protected override void ResponseCallback(byte[] serv_resp)
{
@ -25,7 +25,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_submit_lboard_entry_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_submit_lboard_entry_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}

View File

@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class LoginRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_login_request_t _apiParams;
private readonly LibRCheevos.rc_api_login_request_t _apiParams;
public string Username { get; private set; }
public string ApiToken { get; private set; }
@ -24,7 +24,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_login_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_login_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}

View File

@ -10,7 +10,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class StartGameSessionRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_start_session_request_t _apiParams;
private readonly LibRCheevos.rc_api_start_session_request_t _apiParams;
public StartGameSessionRequest(string username, string apiToken, uint gameId)
{
@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_start_session_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_start_session_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -41,7 +41,7 @@ namespace BizHawk.Client.EmuHawk
private sealed class PingRequest : RCheevoHttpRequest
{
private LibRCheevos.rc_api_ping_request_t _apiParams;
private readonly LibRCheevos.rc_api_ping_request_t _apiParams;
public PingRequest(string username, string apiToken, uint gameId, string richPresence)
{
@ -50,7 +50,7 @@ namespace BizHawk.Client.EmuHawk
public override void DoRequest()
{
var apiParamsResult = _lib.rc_api_init_ping_request(out var api_req, ref _apiParams);
var apiParamsResult = _lib.rc_api_init_ping_request(out var api_req, in _apiParams);
InternalDoRequest(apiParamsResult, ref api_req);
}
@ -79,7 +79,7 @@ namespace BizHawk.Client.EmuHawk
{
if (RichPresenceActive)
{
var len = _lib.rc_runtime_get_richpresence(_runtime, _richPresenceBuffer, new((uint)_richPresenceBuffer.Length), _peekcb, IntPtr.Zero, IntPtr.Zero);
var len = _lib.rc_runtime_get_richpresence(_runtime, _richPresenceBuffer, (uint)_richPresenceBuffer.Length, _peekcb, IntPtr.Zero, IntPtr.Zero);
CurrentRichPresence = Encoding.UTF8.GetString(_richPresenceBuffer, 0, len);
}
else

View File

@ -32,8 +32,8 @@ namespace BizHawk.Client.EmuHawk
// init readers
_filereader = new(OpenFileCallback, SeekFileCallback, TellFileCallback, ReadFileCallback, CloseFileCallback);
_cdreader = new(OpenTrackCallback, ReadSectorCallback, CloseTrackCallback, FirstTrackSectorCallback);
_lib.rc_hash_init_custom_filereader(ref _filereader);
_lib.rc_hash_init_custom_cdreader(ref _cdreader);
_lib.rc_hash_init_custom_filereader(in _filereader);
_lib.rc_hash_init_custom_cdreader(in _cdreader);
_http.DefaultRequestHeaders.UserAgent.ParseAdd($"BizHawk/{VersionInfo.GetEmuVersion()}");
}
@ -380,7 +380,7 @@ namespace BizHawk.Client.EmuHawk
}
}
addr += memFunctions.BankSize;
addr = checked(addr + memFunctions.BankSize);
}
}

View File

@ -139,7 +139,7 @@ namespace BizHawk.Client.EmuHawk
{
addr = FixAddr(addr);
if (addr >= (_domainAddrStart + BankSize))
if (addr >= _domainAddrStart + BankSize)
{
return 0;
}
@ -180,7 +180,8 @@ namespace BizHawk.Client.EmuHawk
WriteFunc = WriteMem;
ReadBlockFunc = ReadMemBlock;
if (bankSize > uint.MaxValue)
// while rcheevos could go all the way to uint.MaxValue, RAIntegration is restricted to int.MaxValue
if (bankSize > int.MaxValue)
{
throw new OverflowException("bankSize is too big!");
}