Compare commits

...

5 Commits

Author SHA1 Message Date
Daniel Nylander
4a856fb026 Merge fc12d99716 into 1c8276197f 2025-02-26 07:00:56 +09:00
FluffyOMC
1c8276197f SSBU DRPC - Stage Editing (#707)
Adds it so the Rich Presence now notices when the player edits a custom
stage!
2025-02-25 15:48:35 -06:00
LotP1
a3596ba858 Reset in-memory JIT cache on game quit + fix Purge PPTC (#709)
Jit cache now fully resets when booting a game multiple times.
This should fix random jit cache crashes.
Also removed some redundant code related to region allocation and fixed
PPTC Purge not fully purging all PPTC files in the backup folder.
2025-02-25 15:34:21 -06:00
Daniel Nylander
fc12d99716 Updated Swedish in locales.json 2025-02-25 07:46:29 +01:00
Evan Husted
3ffcc72117 UI: Fix compatibility list crashing (missing font) 2025-02-22 23:48:47 -06:00
7 changed files with 107 additions and 71 deletions

View File

@@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache
private static JitCacheInvalidation _jitCacheInvalidator;
private static CacheMemoryAllocator _cacheAllocator;
private static List<CacheMemoryAllocator> _cacheAllocators = [];
private static readonly List<CacheEntry> _cacheEntries = [];
@@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache
public static void Initialize(IJitMemoryAllocator allocator)
{
if (_initialized)
{
return;
}
lock (_lock)
{
if (_initialized)
{
return;
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.RemoveFunctionTableHandler(
_jitRegions[0].Pointer);
}
for (int i = 0; i < _jitRegions.Count; i++)
{
_jitRegions[i].Dispose();
}
_jitRegions.Clear();
_cacheAllocators.Clear();
}
else
{
_initialized = true;
}
_activeRegionIndex = 0;
ReservedRegion firstRegion = new(allocator, CacheSize);
_jitRegions.Add(firstRegion);
_activeRegionIndex = 0;
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
_cacheAllocators.Add(firstCacheAllocator);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
}
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.InstallFunctionTableHandler(
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
);
}
_initialized = true;
}
}
@@ -136,7 +147,7 @@ namespace ARMeilleure.Translation.Cache
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
@@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache
{
codeSize = AlignCodeSize(codeSize);
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
if (allocOffset >= 0)
{
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset >= 0)
{
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
_activeRegionIndex = i;
return allocOffset;
}
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
return allocOffset;
}
int exhaustedRegion = _activeRegionIndex;
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex;
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation).");
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
if (allocOffsetNew < 0)
{
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");

View File

@@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache
nint context,
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe partial bool RtlDeleteFunctionTable(
ulong tableIdentifier);
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
private static int _sizeOfRuntimeFunction;
@@ -91,6 +96,23 @@ namespace ARMeilleure.Translation.Cache
}
}
public static void RemoveFunctionTableHandler(nint codeCachePointer)
{
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
bool result;
unsafe
{
result = RtlDeleteFunctionTable(codeCachePtr | 3);
}
if (!result)
{
throw new InvalidOperationException("Failure removing function table callback.");
}
}
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
{
int offset = (int)((long)controlPc - context.ToInt64());

View File

@@ -464,7 +464,7 @@
"pl_PL": "",
"pt_BR": "Abrir Pasta de Capturas de Tela",
"ru_RU": "Открыть папку со скриншотами",
"sv_SE": "",
"sv_SE": "Öppna skärmbildsmappen",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Відкрити теку скріншотів",
@@ -1564,7 +1564,7 @@
"pl_PL": "",
"pt_BR": "Desenvolvido por {0}",
"ru_RU": "Разработана {0}",
"sv_SE": "",
"sv_SE": "Utvecklat av {0}",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Розроблено: {0}",
@@ -1864,7 +1864,7 @@
"pl_PL": "",
"pt_BR": "Compatibilidade:",
"ru_RU": "Совместимость:",
"sv_SE": "",
"sv_SE": "Kompatibilitet:",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Сумісність:",
@@ -1889,7 +1889,7 @@
"pl_PL": "",
"pt_BR": "ID do Título:",
"ru_RU": "ID приложения",
"sv_SE": "",
"sv_SE": "Titel-id:",
"th_TH": "",
"tr_TR": "",
"uk_UA": "ID гри:",
@@ -1914,7 +1914,7 @@
"pl_PL": "",
"pt_BR": "Jogos Hospedados: {0}",
"ru_RU": "Запущенно игр: {0}",
"sv_SE": "",
"sv_SE": "Värdskap för spel: {0}",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Розміщені ігри: {0}",
@@ -1939,7 +1939,7 @@
"pl_PL": "",
"pt_BR": "Jogadores Online: {0}",
"ru_RU": "Игроков онлайн: {0}",
"sv_SE": "",
"sv_SE": "Online-spelare: {0}",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Гравців онлайн: {0}",
@@ -2289,7 +2289,7 @@
"pl_PL": "",
"pt_BR": "Limpar Cache PPTC",
"ru_RU": "Очистить кэш PPTC",
"sv_SE": "",
"sv_SE": "Rensa PPTC-cache",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Очистити кеш PPTC",
@@ -2314,7 +2314,7 @@
"pl_PL": "",
"pt_BR": "Apaga os arquivos de cache PPTC do aplicativo",
"ru_RU": "Удаляет все файлы кэша PPTC для приложения",
"sv_SE": "",
"sv_SE": "Tar bort alla PPTC-cachefiler för applikationen",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Видаляє всі файли кешу PPTC для застосунку",
@@ -2789,7 +2789,7 @@
"pl_PL": "",
"pt_BR": "Mostrar Dados de Compatibilidade",
"ru_RU": "Показать записи о совместимости",
"sv_SE": "",
"sv_SE": "Visa kompatibilitetspost",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Iнформація про сумісність",
@@ -2814,7 +2814,7 @@
"pl_PL": "",
"pt_BR": "Exibe o jogo selecionado na Lista de Compatibilidade, que normalmente pode ser acessada pelo menu Ajuda.",
"ru_RU": "Отобразить выбранную игру в списке совместимости, доступ к которому вы обычно можете получить через меню Справки.",
"sv_SE": "",
"sv_SE": "Visa valt spel i kompatibilitetslistan som du normalt sett kan komma åt via hjälpmenyn.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Показати цю гру в Списку Сумісності. Список сумісності також можна зайти в меню Довідки.",
@@ -2839,7 +2839,7 @@
"pl_PL": "",
"pt_BR": "Mostrar Informações do Jogo",
"ru_RU": "Показать информацию об игре",
"sv_SE": "",
"sv_SE": "Visa spelinformation",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Інформація про гру",
@@ -2864,7 +2864,7 @@
"pl_PL": "",
"pt_BR": "Exibe estatísticas e detalhes sobre o jogo selecionado.",
"ru_RU": "Показывать статистику и подробную информацию о выбранной игре.",
"sv_SE": "",
"sv_SE": "Visa statistik och detaljer om det aktuella spelet.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Показати статистику та деталі обраної гри.",
@@ -3389,7 +3389,7 @@
"pl_PL": "",
"pt_BR": "Verificar Atualizações:",
"ru_RU": "Проверка наличия обновлений",
"sv_SE": "",
"sv_SE": "Leta efter uppdateringar:",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Перевірка оновлень:",
@@ -3414,7 +3414,7 @@
"pl_PL": "",
"pt_BR": "Desligado",
"ru_RU": "Отключить",
"sv_SE": "",
"sv_SE": "Av",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Вимкнути",
@@ -3439,7 +3439,7 @@
"pl_PL": "",
"pt_BR": "Ao Abrir",
"ru_RU": "При запуске",
"sv_SE": "",
"sv_SE": "Fråga",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Запитувати щоразу",
@@ -3464,7 +3464,7 @@
"pl_PL": "",
"pt_BR": "2° Plano",
"ru_RU": "В фоне",
"sv_SE": "",
"sv_SE": "Bakgrund",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Оновлювати в фоні",
@@ -3489,7 +3489,7 @@
"pl_PL": "",
"pt_BR": "Ao Perder o Foco:",
"ru_RU": "При выходе эмулятора из фокуса",
"sv_SE": "",
"sv_SE": "När emulatorn tappar fokus:",
"th_TH": "",
"tr_TR": "",
"uk_UA": "При втраті фокуса емулятором:",
@@ -3514,7 +3514,7 @@
"pl_PL": "",
"pt_BR": "Não Fazer Nada",
"ru_RU": "Ничего не делать",
"sv_SE": "",
"sv_SE": "Gör ingenting",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Нічого не робити",
@@ -3539,7 +3539,7 @@
"pl_PL": "",
"pt_BR": "Bloquear Controles",
"ru_RU": "Блокировать управление",
"sv_SE": "",
"sv_SE": "Blockera inmatning",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Блокувати введення",
@@ -3564,7 +3564,7 @@
"pl_PL": "",
"pt_BR": "Ficar Mudo",
"ru_RU": "Отключить звук",
"sv_SE": "",
"sv_SE": "Stäng av ljudet",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Вимкнути звук",
@@ -3589,7 +3589,7 @@
"pl_PL": "",
"pt_BR": "Bloquear Controles & Ficar Mudo",
"ru_RU": "Блокировать управление и отключить звук",
"sv_SE": "",
"sv_SE": "Blockera inmatningar och stäng av ljudet",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Блокувати введення та Вимкнути звук",
@@ -3614,7 +3614,7 @@
"pl_PL": "",
"pt_BR": "Pausar a Emulação",
"ru_RU": "Поставить паузу",
"sv_SE": "",
"sv_SE": "Pausa emuleringen",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Поставити на паузу",
@@ -3689,7 +3689,7 @@
"pl_PL": "",
"pt_BR": "Desativar Controles Quando Estiver Fora de Foco",
"ru_RU": "Отключает управление при выходе из фокуса",
"sv_SE": "",
"sv_SE": "Inaktivera inmatning när fokus tappas",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
@@ -4714,7 +4714,7 @@
"pl_PL": "",
"pt_BR": "Sincronizar com o Sistema PC",
"ru_RU": "Соответствовать времени в системе",
"sv_SE": "",
"sv_SE": "Matcha systemtid",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
@@ -5139,7 +5139,7 @@
"pl_PL": "",
"pt_BR": "Ignorar Applet do Controlador",
"ru_RU": "Игнорировать апплет контроллера",
"sv_SE": "",
"sv_SE": "Ignorera kontroller-applet",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Ігнорувати Аплет Контролера",
@@ -5989,7 +5989,7 @@
"pl_PL": "",
"pt_BR": "Habilitar Logs da IU",
"ru_RU": "Включить журнал интерфейса",
"sv_SE": "",
"sv_SE": "Aktivera gränssnittsloggar",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Увімкнути журнали інтерфейсу",
@@ -6389,7 +6389,7 @@
"pl_PL": "",
"pt_BR": "Redefinir Configurações",
"ru_RU": "Сбросить настройки",
"sv_SE": "",
"sv_SE": "Nollställ inställningar",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Скинути налаштування",
@@ -6414,7 +6414,7 @@
"pl_PL": "",
"pt_BR": "Quero redefinir minhas configurações.",
"ru_RU": "Я хочу сбросить свои настройки.",
"sv_SE": "",
"sv_SE": "Jag vill nollställa mina inställningar.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Я хочу скинути налаштування.",
@@ -8389,7 +8389,7 @@
"pl_PL": "",
"pt_BR": "Velocidade do Arco-íris",
"ru_RU": "Скорость переливания",
"sv_SE": "",
"sv_SE": "Regnbågshastighet",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
@@ -13664,7 +13664,7 @@
"pl_PL": "",
"pt_BR": "Você está prestes a limpar todos os dados PPTC de:\n\n{0}\n\nTem certeza de que deseja continuar?",
"ru_RU": "Вы собираетесь удалить все данные PPTC из:\n\n{0}\n\nВы уверены, что хотите продолжить?",
"sv_SE": "",
"sv_SE": "Du är på väg att ta bort allt PPTC-data från:\n\n{0}\n\nÄr du säker på att du vill fortsätta?",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Ви збираєтесь видалити всі дані PPTC з:\n\n{0}\n\nБажаєте продовжити цю операцію?",
@@ -16514,7 +16514,7 @@
"pl_PL": "",
"pt_BR": "A caixa de diálogo do Applet do controlador não aparecerá se o controle for desconectado enquanto um aplicativo estiver em execução.\n\nDeixe a opção DESLIGADO se não tiver certeza.",
"ru_RU": "Диалоговое окно апплета контроллера не будет отображаться, если геймпад отключен во время работы приложения.\n\nОставьте выключенным, если не уверены.",
"sv_SE": "",
"sv_SE": "Handkontroller-appleten kommer inte att visas om gamepaden är frånkopplad under tiden en applikation körs.\n\nLämna AV om du är osäker.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Діалогове вікно Аплету Контролера не з'явиться, якщо геймпад було відключено під час роботи програми.\n\nЗалиште вимкненим якщо не впевнені.",
@@ -16989,7 +16989,7 @@
"pl_PL": "",
"pt_BR": "Imprime mensagens de log do Avalonia (UI) no console.",
"ru_RU": "Выводит сообщения журнала Avalonia (интерфейс) в консоли.",
"sv_SE": "",
"sv_SE": "Skriver ut loggmeddelanden från Avalonia (användargränssnittet) i konsollen.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Виводити повідомлення журналу Avalonia (UI) в консоль",
@@ -17189,7 +17189,7 @@
"pl_PL": "",
"pt_BR": "Abre a pasta de capturas de tela do Ryujinx",
"ru_RU": "Открывает папку скриншотов Ryujinx",
"sv_SE": "",
"sv_SE": "Öppna Ryujinx skärmbildsmapp",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Відкрити теку куди зберігаються скріншоти Ryujinx",
@@ -17939,7 +17939,7 @@
"pl_PL": "",
"pt_BR": "Atualização Disponível!",
"ru_RU": "Доступно обновление!",
"sv_SE": "",
"sv_SE": "Uppdatering finns tillgänglig!",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Доступне оновлення!",
@@ -23889,7 +23889,7 @@
"pl_PL": "",
"pt_BR": "Inicializa e roda sem travamentos ou bugs de GPU de qualquer tipo, e em uma velocidade rápida o suficiente para ser aproveitado em um PC comum.",
"ru_RU": "Запускается и работает без любого рода сбоев или графисечких ошибок и на скорости, достаточной для работы на обычном ПК.",
"sv_SE": "",
"sv_SE": "Startar upp och spelas utan några krascher eller GPU-fel av några slag och med en hastighet som är snabb nog för bra upplevelse på en genomsnittlig PC.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Запускається та оптимально працює (без збоїв або графічних багів) на середньостатистичному комп'ютері.",
@@ -23914,7 +23914,7 @@
"pl_PL": "",
"pt_BR": "Inicializa e entra no jogo, mas sofre de um ou mais dos seguintes: travamentos, deadlocks, bugs de GPU, áudio ruim que distrai ou é simplesmente muito lento. O jogo ainda pode ser jogado até o fim, mas não da forma como foi criado para ser jogado.",
"ru_RU": "Запускается и работает, но возникает одна или несколько из следующих проблем: сбои, взаимоблокировки, ошибки GPU, отвлекающие звуки или просто слишком медленная работа. Возможно, игру всё же удастся пройти до конца, но не так, как она задумана.",
"sv_SE": "",
"sv_SE": "Startar och går in i spelet men lider av ett eller flera av följande: kraschar, deadlocks, GPU-buggar, distraherande dåligt ljud eller är helt enkelt för långsamt. Spelet kan fortfarande spelas hela vägen igenom, men inte så som spelet är avsett att spelas.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Запускається, але в грі на вас чекатимуть одна або декілька наступних проблем: збої, зависання, графічні баги, спотворений звук або ж гра загалом працюватиме надто повільно. Можливо, її все ще можна пройти, але досвід буде не найкращим.",
@@ -23939,7 +23939,7 @@
"pl_PL": "",
"pt_BR": "Inicializa e passa da tela de título, mas não entra no jogo principal.",
"ru_RU": "Загружается титульный экран и можно перейти дальше, но сама игра не работает.",
"sv_SE": "",
"sv_SE": "Startar upp och går förbi titelskärmen men tar sig inte in i huvudspelet.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Запускається та проходить початковий екран, але пограти не вийде.",
@@ -23964,7 +23964,7 @@
"pl_PL": "",
"pt_BR": "Inizializa, mas não passa da tela de título.",
"ru_RU": "Загружается, но не проходит дальше титульного экрана.",
"sv_SE": "",
"sv_SE": "Startar upp men tar sig inte förbi titelskärmen.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Запускається, але не відображає навіть початкового екрану.",
@@ -23989,7 +23989,7 @@
"pl_PL": "",
"pt_BR": "Não inicializa ou não mostra sinais de atividade.",
"ru_RU": "Не запускается или не подаёт признаков жизни.",
"sv_SE": "",
"sv_SE": "Startar inte upp eller visar någon form av aktivitet.",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Взагалі не запускається.",
@@ -24039,7 +24039,7 @@
"pl_PL": "",
"pt_BR": "Imagem da Presença do Discord",
"ru_RU": "Изображение для статуса активности",
"sv_SE": "",
"sv_SE": "Bild för Rich Presence",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Зображення картки активності Discord",
@@ -24064,7 +24064,7 @@
"pl_PL": "",
"pt_BR": "Presença Dinâmica do Discord",
"ru_RU": "Динамический статус активности",
"sv_SE": "",
"sv_SE": "Dynamisk Rich Presence",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Динамічна картка активності Discord",

View File

@@ -112,6 +112,10 @@
<AvaloniaResource Include="UI\**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Bold.ttf" />
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-BoldItalic.ttf" />
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Italic.ttf" />
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Regular.ttf" />
<AvaloniaResource Include="Assets\Fonts\SegoeFluentIcons.ttf" />
<AvaloniaResource Include="Assets\Styles\Themes.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -200,7 +200,7 @@ namespace Ryujinx.Ava.UI.Controls
if (backupDir.Exists)
{
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
cacheFiles.AddRange(mainDir.EnumerateFiles("*.info"));
cacheFiles.AddRange(backupDir.EnumerateFiles("*.info"));
}
if (cacheFiles.Count > 0)

View File

@@ -115,6 +115,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport
return $"Achievement Unlocked - ID: {anniversary}";
}
if (values.Matched.ContainsKey("is_created"))
{
return "Edited a Custom Stage!";
}
if (values.Matched.ContainsKey("adv_slot"))
{
return

View File

@@ -71,7 +71,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
[
// Metadata to figure out what PlayReport we have.
"match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count",
"adv_slot",
"adv_slot", "is_created",
// List of Fighters
"player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter",
"player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter",