Merge pull request #65 from bmarcott/nmarcott_format

apply clang-format to all .cpp and .h files containing the word slippi
This commit is contained in:
David Liu 2021-01-19 18:26:07 -05:00 committed by GitHub
commit a557edb283
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1616 additions and 1419 deletions

View file

@ -1,17 +1,20 @@
#include <string>
#include <codecvt>
#include <locale>
#include <string>
#include "SlippiGame.h"
namespace Slippi {
namespace Slippi
{
//**********************************************************************
//* Event Handlers
//**********************************************************************
//The read operators will read a value and increment the index so the next read will read in the correct location
uint8_t readByte(uint8_t* a, int& idx, uint32_t maxSize, uint8_t defaultValue) {
if (idx >= (int)maxSize) {
// The read operators will read a value and increment the index so the next read
// will read in the correct location
uint8_t readByte(uint8_t* a, int& idx, uint32_t maxSize, uint8_t defaultValue)
{
if (idx >= (int)maxSize)
{
idx += 1;
return defaultValue;
}
@ -19,8 +22,10 @@ namespace Slippi {
return a[idx++];
}
uint16_t readHalf(uint8_t* a, int& idx, uint32_t maxSize, uint16_t defaultValue) {
if (idx >= (int)maxSize) {
uint16_t readHalf(uint8_t* a, int& idx, uint32_t maxSize, uint16_t defaultValue)
{
if (idx >= (int)maxSize)
{
idx += 2;
return defaultValue;
}
@ -30,8 +35,10 @@ namespace Slippi {
return value;
}
uint32_t readWord(uint8_t* a, int& idx, uint32_t maxSize, uint32_t defaultValue) {
if (idx >= (int)maxSize) {
uint32_t readWord(uint8_t* a, int& idx, uint32_t maxSize, uint32_t defaultValue)
{
if (idx >= (int)maxSize)
{
idx += 4;
return defaultValue;
}
@ -41,21 +48,25 @@ namespace Slippi {
return value;
}
float readFloat(uint8_t* a, int& idx, uint32_t maxSize, float defaultValue) {
float readFloat(uint8_t* a, int& idx, uint32_t maxSize, float defaultValue)
{
uint32_t bytes = readWord(a, idx, maxSize, *(uint32_t*)(&defaultValue));
return *(float*)(&bytes);
}
void handleGameInit(Game* game, uint32_t maxSize) {
void handleGameInit(Game* game, uint32_t maxSize)
{
int idx = 0;
// Read version number
for (int i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++)
{
game->version[i] = readByte(data, idx, maxSize, 0);
}
// Read entire game info header
for (int i = 0; i < GAME_INFO_HEADER_SIZE; i++) {
for (int i = 0; i < GAME_INFO_HEADER_SIZE; i++)
{
game->settings.header[i] = readWord(data, idx, maxSize, 0);
}
@ -64,15 +75,18 @@ namespace Slippi {
// Read UCF toggle bytes
bool shouldRead = game->version[0] >= 1;
for (int i = 0; i < UCF_TOGGLE_SIZE; i++) {
for (int i = 0; i < UCF_TOGGLE_SIZE; i++)
{
uint32_t value = shouldRead ? readWord(data, idx, maxSize, 0) : 0;
game->settings.ucfToggles[i] = value;
}
// Read nametag for each player
std::array<std::array<uint16_t, NAMETAG_SIZE>, 4> playerNametags;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < NAMETAG_SIZE; j++) {
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < NAMETAG_SIZE; j++)
{
playerNametags[i][j] = readHalf(data, idx, maxSize, 0);
}
}
@ -86,13 +100,16 @@ namespace Slippi {
// Pull header data into struct
int player1Pos = 24; // This is the index of the first players character info
std::array<uint32_t, Slippi::GAME_INFO_HEADER_SIZE> gameInfoHeader = game->settings.header;
for (int i = 0; i < 4; i++) {
// this is the position in the array that this player's character info is stored
for (int i = 0; i < 4; i++)
{
// this is the position in the array that this player's character info is
// stored
int pos = player1Pos + (9 * i);
uint32_t playerInfo = gameInfoHeader[pos];
uint8_t playerType = (playerInfo & 0x00FF0000) >> 16;
if (playerType == 0x3) {
if (playerType == 0x3)
{
// Player type 3 is an empty slot
continue;
}
@ -114,13 +131,15 @@ namespace Slippi {
auto majorVersion = game->version[0];
auto minorVersion = game->version[1];
if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 1)) {
if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 1))
{
// After version 3.1.0 we added a dynamic gecko loading process. These
// are needed before starting the game. areSettingsLoaded will be set
// to true when they are received
game->areSettingsLoaded = false;
}
else if (majorVersion > 1 || (majorVersion == 1 && minorVersion >= 6)) {
else if (majorVersion > 1 || (majorVersion == 1 && minorVersion >= 6))
{
// Indicate settings loaded immediately if after version 1.6.0
// Sheik game info was added in this version and so we no longer
// need to wait
@ -128,7 +147,8 @@ namespace Slippi {
}
}
void handleGeckoList(Game* game, uint32_t maxSize) {
void handleGeckoList(Game* game, uint32_t maxSize)
{
game->settings.geckoCodes.clear();
game->settings.geckoCodes.insert(game->settings.geckoCodes.end(), data, data + maxSize);
@ -136,7 +156,8 @@ namespace Slippi {
game->areSettingsLoaded = true;
}
void handleFrameStart(Game* game, uint32_t maxSize) {
void handleFrameStart(Game* game, uint32_t maxSize)
{
int idx = 0;
// Check frame count
@ -157,7 +178,8 @@ namespace Slippi {
game->framesByIndex[frameCount] = frame;
}
void handlePreFrameUpdate(Game* game, uint32_t maxSize) {
void handlePreFrameUpdate(Game* game, uint32_t maxSize)
{
int idx = 0;
// Check frame count
@ -168,7 +190,8 @@ namespace Slippi {
FrameData* frame = frameUniquePtr.get();
bool isNewFrame = true;
if (game->framesByIndex.count(frameCount)) {
if (game->framesByIndex.count(frameCount))
{
// If this frame already exists, get the current frame
frame = game->frames.back().get();
isNewFrame = false;
@ -203,7 +226,8 @@ namespace Slippi {
p.lTrigger = readFloat(data, idx, maxSize, 0);
p.rTrigger = readFloat(data, idx, maxSize, 0);
if (asmEvents[EVENT_PRE_FRAME_UPDATE] >= 59) {
if (asmEvents[EVENT_PRE_FRAME_UPDATE] >= 59)
{
p.joystickXRaw = readByte(data, idx, maxSize, 0);
}
@ -218,27 +242,31 @@ namespace Slippi {
target->operator[](playerSlot) = p;
// Add frame to game
if (isNewFrame) {
if (isNewFrame)
{
frame->numSinceStart = game->frames.size();
game->frames.push_back(std::move(frameUniquePtr));
game->framesByIndex[frameCount] = frame;
}
}
void handlePostFrameUpdate(Game* game, uint32_t maxSize) {
void handlePostFrameUpdate(Game* game, uint32_t maxSize)
{
int idx = 0;
// Check frame count
int32_t frameCount = readWord(data, idx, maxSize, 0);
FrameData* frame;
if (game->framesByIndex.count(frameCount)) {
if (game->framesByIndex.count(frameCount))
{
// If this frame already exists, get the current frame
frame = game->frames.back().get();
}
// As soon as a post frame update happens, we know we have received all the inputs
// This is used to determine if a frame is ready to be used for a replay (for mirroring)
// As soon as a post frame update happens, we know we have received all the
// inputs This is used to determine if a frame is ready to be used for a
// replay (for mirroring)
frame->inputsFullyFetched = true;
uint8_t playerSlot = readByte(data, idx, maxSize, 0);
@ -249,55 +277,67 @@ namespace Slippi {
p->internalCharacterId = readByte(data, idx, maxSize, 0);
// Check if a player started as sheik and update
if (frameCount == GAME_FIRST_FRAME && p->internalCharacterId == GAME_SHEIK_INTERNAL_ID) {
if (frameCount == GAME_FIRST_FRAME && p->internalCharacterId == GAME_SHEIK_INTERNAL_ID)
{
game->settings.players[playerSlot].characterId = GAME_SHEIK_EXTERNAL_ID;
}
// Set settings loaded if this is the last character
if (frameCount == GAME_FIRST_FRAME) {
if (frameCount == GAME_FIRST_FRAME)
{
uint8_t lastPlayerIndex = 0;
for (auto it = frame->players.begin(); it != frame->players.end(); ++it) {
if (it->first <= lastPlayerIndex) {
for (auto it = frame->players.begin(); it != frame->players.end(); ++it)
{
if (it->first <= lastPlayerIndex)
{
continue;
}
lastPlayerIndex = it->first;
}
if (playerSlot >= lastPlayerIndex) {
if (playerSlot >= lastPlayerIndex)
{
game->areSettingsLoaded = true;
}
}
}
void handleGameEnd(Game* game, uint32_t maxSize) {
void handleGameEnd(Game* game, uint32_t maxSize)
{
int idx = 0;
game->winCondition = readByte(data, idx, maxSize, 0);
}
// This function gets the position where the raw data starts
int getRawDataPosition(std::ifstream* f) {
int getRawDataPosition(std::ifstream* f)
{
char buffer[2];
f->seekg(0, std::ios::beg);
f->read(buffer, 2);
if (buffer[0] == 0x36) {
if (buffer[0] == 0x36)
{
return 0;
}
if (buffer[0] != '{') {
if (buffer[0] != '{')
{
// TODO: Do something here to cause an error
return 0;
}
// TODO: Read ubjson file to find the "raw" element and return the start of it
// TODO: For now since raw is the first element the data will always start at 15
// TODO: For now since raw is the first element the data will always start at
// 15
return 15;
}
uint32_t getRawDataLength(std::ifstream* f, int position, int fileSize) {
if (position == 0) {
uint32_t getRawDataLength(std::ifstream* f, int position, int fileSize)
{
if (position == 0)
{
return fileSize;
}
@ -310,23 +350,23 @@ namespace Slippi {
return length;
}
std::unordered_map<uint8_t, uint32_t> getMessageSizes(std::ifstream* f, int position) {
std::unordered_map<uint8_t, uint32_t> getMessageSizes(std::ifstream* f, int position)
{
char buffer[2];
f->seekg(position, std::ios::beg);
f->read(buffer, 2);
if (buffer[0] != EVENT_PAYLOAD_SIZES) {
if (buffer[0] != EVENT_PAYLOAD_SIZES)
{
return {};
}
int payloadLength = buffer[1];
std::unordered_map<uint8_t, uint32_t> messageSizes = {
{ EVENT_PAYLOAD_SIZES, payloadLength }
};
std::unordered_map<uint8_t, uint32_t> messageSizes = {{EVENT_PAYLOAD_SIZES, payloadLength}};
std::vector<char> messageSizesBuffer(payloadLength - 1);
f->read(&messageSizesBuffer[0], payloadLength - 1);
for (int i = 0; i < payloadLength - 1; i += 3) {
for (int i = 0; i < payloadLength - 1; i += 3)
{
uint8_t command = messageSizesBuffer[i];
// Extract the bytes in u8s. Without this the chars don't or together well
@ -340,8 +380,10 @@ namespace Slippi {
return messageSizes;
}
void SlippiGame::processData() {
if (isProcessingComplete) {
void SlippiGame::processData()
{
if (isProcessingComplete)
{
// If we have finished processing this file, return
return;
}
@ -349,17 +391,20 @@ namespace Slippi {
// This function will process as much data as possible
int startPos = (int)file->tellg();
file->seekg(startPos);
if (startPos == 0) {
if (startPos == 0)
{
file->seekg(0, std::ios::end);
int len = (int)file->tellg();
if (len < 2) {
if (len < 2)
{
// If we can't read message sizes payload size yet, return
return;
}
int rawDataPos = getRawDataPosition(file.get());
int rawDataLen = len - rawDataPos;
if (rawDataLen < 2) {
if (rawDataLen < 2)
{
// If we don't have enough raw data yet to read the replay file, return
// Reset to begining so that the startPos condition will be hit again
file->seekg(0);
@ -373,7 +418,8 @@ namespace Slippi {
file->read(buffer, 2);
file->seekg(startPos);
auto messageSizesSize = (int)buffer[1];
if (rawDataLen < messageSizesSize) {
if (rawDataLen < messageSizesSize)
{
// If we haven't received the full payload sizes message, return
// Reset to begining so that the startPos condition will be hit again
file->seekg(0);
@ -391,7 +437,8 @@ namespace Slippi {
// log << "Size to read: " << sizeToRead << "\n";
// log << "Start Pos: " << startPos << "\n";
// log << "End Pos: " << endPos << "\n\n";
if (sizeToRead <= 0) {
if (sizeToRead <= 0)
{
return;
}
@ -399,7 +446,8 @@ namespace Slippi {
file->read(&newData[0], sizeToRead);
int newDataPos = 0;
while (newDataPos < sizeToRead) {
while (newDataPos < sizeToRead)
{
auto command = newData[newDataPos];
auto payloadSize = asmEvents[command];
@ -408,7 +456,8 @@ namespace Slippi {
// log << "Command: " << buff << " | Payload Size: " << payloadSize << "\n";
auto remainingLen = sizeToRead - newDataPos;
if (remainingLen < ((int)payloadSize + 1)) {
if (remainingLen < ((int)payloadSize + 1))
{
// Here we don't have enough data to read the whole payload
// Will be processed after getting more data (hopefully)
file->seekg(-remainingLen, std::ios::cur);
@ -421,7 +470,8 @@ namespace Slippi {
uint32_t outerPayloadSize = payloadSize;
// Handle a split message, combining in until we possess the entire message
if (command == EVENT_SPLIT_MESSAGE) {
if (command == EVENT_SPLIT_MESSAGE)
{
if (shouldResetSplitMessageBuf)
{
splitMessageBuf.clear();
@ -443,7 +493,8 @@ namespace Slippi {
}
}
switch (command) {
switch (command)
{
case EVENT_GAME_INIT:
handleGameInit(game.get(), payloadSize);
break;
@ -479,7 +530,8 @@ namespace Slippi {
}
}
std::unique_ptr<SlippiGame> SlippiGame::FromFile(std::string path) {
std::unique_ptr<SlippiGame> SlippiGame::FromFile(std::string path)
{
auto result = std::make_unique<SlippiGame>();
result->game = std::make_unique<Game>();
result->path = path;
@ -493,7 +545,8 @@ namespace Slippi {
#endif
// result->log.open("log.txt");
if (!result->file->is_open()) {
if (!result->file->is_open())
{
return nullptr;
}
@ -511,16 +564,19 @@ namespace Slippi {
return std::move(result);
}
bool SlippiGame::IsProcessingComplete() {
bool SlippiGame::IsProcessingComplete()
{
return isProcessingComplete;
}
bool SlippiGame::AreSettingsLoaded() {
bool SlippiGame::AreSettingsLoaded()
{
processData();
return game->areSettingsLoaded;
}
bool SlippiGame::DoesFrameExist(int32_t frame) {
bool SlippiGame::DoesFrameExist(int32_t frame)
{
processData();
return (bool)game->framesByIndex.count(frame);
}
@ -530,13 +586,16 @@ namespace Slippi {
return game->version;
}
FrameData* SlippiGame::GetFrame(int32_t frame) {
FrameData* SlippiGame::GetFrame(int32_t frame)
{
// Get the frame we want
return game->framesByIndex.at(frame);
}
FrameData* SlippiGame::GetFrameAt(uint32_t pos) {
if (pos >= game->frames.size()) {
FrameData* SlippiGame::GetFrameAt(uint32_t pos)
{
if (pos >= game->frames.size())
{
return nullptr;
}
@ -544,17 +603,20 @@ namespace Slippi {
return game->frames[pos].get();
}
int32_t SlippiGame::GetLatestIndex() {
int32_t SlippiGame::GetLatestIndex()
{
processData();
return game->frameCount;
}
GameSettings* SlippiGame::GetSettings() {
GameSettings* SlippiGame::GetSettings()
{
processData();
return &game->settings;
}
bool SlippiGame::DoesPlayerExist(int8_t port) {
bool SlippiGame::DoesPlayerExist(int8_t port)
{
return game->settings.players.find(port) != game->settings.players.end();
}
}
} // namespace Slippi

View file

@ -1,14 +1,15 @@
#pragma once
#include <string>
#include <array>
#include <vector>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace Slippi {
namespace Slippi
{
const uint8_t EVENT_SPLIT_MESSAGE = 0x10;
const uint8_t EVENT_PAYLOAD_SIZES = 0x35;
const uint8_t EVENT_GAME_INIT = 0x36;
@ -30,8 +31,10 @@ namespace Slippi {
static uint8_t* data;
typedef struct {
// Every player update has its own rng seed because it might change in between players
typedef struct
{
// Every player update has its own rng seed because it might change in between
// players
uint32_t randomSeed;
uint8_t internalCharacterId;
@ -52,17 +55,20 @@ namespace Slippi {
float cstickX;
float cstickY;
float trigger;
uint32_t buttons; //This will include multiple "buttons" pressed on special buttons. For example I think pressing z sets 3 bits
uint32_t buttons; // This will include multiple "buttons" pressed on special
// buttons. For example I think pressing z sets 3 bits
// This is extra controller information
uint16_t physicalButtons; //A better representation of what a player is actually pressing
uint16_t physicalButtons; // A better representation of what a player is
// actually pressing
float lTrigger;
float rTrigger;
uint8_t joystickXRaw;
} PlayerFrameData;
typedef struct FrameData {
typedef struct FrameData
{
int32_t frame;
uint32_t numSinceStart;
bool randomSeedExists = false;
@ -72,7 +78,8 @@ namespace Slippi {
std::unordered_map<uint8_t, PlayerFrameData> followers;
} FrameData;
typedef struct {
typedef struct
{
// Static data
uint8_t characterId;
uint8_t characterColor;
@ -81,7 +88,8 @@ namespace Slippi {
std::array<uint16_t, NAMETAG_SIZE> nametag;
} PlayerSettings;
typedef struct {
typedef struct
{
uint16_t stage; // Stage ID
uint32_t randomSeed;
std::array<uint32_t, GAME_INFO_HEADER_SIZE> header;
@ -92,7 +100,8 @@ namespace Slippi {
std::vector<uint8_t> geckoCodes;
} GameSettings;
typedef struct Game {
typedef struct Game
{
std::array<uint8_t, 4> version;
std::unordered_map<int32_t, FrameData*> framesByIndex;
std::vector<std::unique_ptr<FrameData>> frames;
@ -107,13 +116,11 @@ namespace Slippi {
// TODO: This shouldn't be static. Doesn't matter too much atm because we always
// TODO: only read one file at a time
static std::unordered_map<uint8_t, uint32_t> asmEvents = {
{ EVENT_GAME_INIT, 320 },
static std::unordered_map<uint8_t, uint32_t> asmEvents = {{EVENT_GAME_INIT, 320},
{EVENT_PRE_FRAME_UPDATE, 58},
{EVENT_POST_FRAME_UPDATE, 33},
{EVENT_GAME_END, 1},
{ EVENT_FRAME_START, 8 }
};
{EVENT_FRAME_START, 8}};
class SlippiGame
{
@ -128,6 +135,7 @@ namespace Slippi {
GameSettings* GetSettings();
bool DoesPlayerExist(int8_t port);
bool IsProcessingComplete();
private:
std::unique_ptr<Game> game;
std::unique_ptr<std::ifstream> file;
@ -140,4 +148,4 @@ namespace Slippi {
bool isProcessingComplete = false;
void processData();
};
}
} // namespace Slippi

View file

@ -2,10 +2,9 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <semver/include/semver200.h>
#include <utility> // std::move
#include <algorithm>
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
@ -17,17 +16,17 @@
#include "Common/Thread.h"
#include "Common/Version.h"
#include "Core/Core.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/Host.h"
#include "Core/HW/EXI/EXI_DeviceSlippi.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
#include "Core/Host.h"
#include "Core/NetPlayClient.h"
#include "Core/Slippi/SlippiReplayComm.h"
#include "Core/Slippi/SlippiPlayback.h"
#include "Core/Slippi/SlippiReplayComm.h"
#include "Core/State.h"
#define FRAME_INTERVAL 900
@ -43,12 +42,13 @@ extern std::unique_ptr<SlippiReplayComm> g_replayComm;
bool isLocalConnected = false;
#endif
namespace ExpansionInterface {
namespace ExpansionInterface
{
static std::unordered_map<u8, std::string> slippi_names;
static std::unordered_map<u8, std::string> slippi_connect_codes;
template <typename T> bool isFutureReady(std::future<T>& t)
template <typename T>
bool isFutureReady(std::future<T>& t)
{
return t.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
@ -120,60 +120,76 @@ CEXISlippi::CEXISlippi()
// MnMaAll.usd
std::string origStr;
std::string modifiedStr;
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.usd", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll-new.usd",
modifiedStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.usd", origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll-new.usd", modifiedStr);
std::vector<u8> orig(origStr.begin(), origStr.end());
std::vector<u8> modified(modifiedStr.begin(), modifiedStr.end());
auto diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.usd.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.usd.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\MnMaAll.usd.diff");
// MnExtAll.usd
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.usd", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll-new.usd", modifiedStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.usd",
origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll-new.usd", modifiedStr);
orig = std::vector<u8>(origStr.begin(), origStr.end());
modified = std::vector<u8>(modifiedStr.begin(), modifiedStr.end());
diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.usd.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.usd.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\MnExtAll.usd.diff");
// SdMenu.usd
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.usd", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu-new.usd", modifiedStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.usd",
origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu-new.usd", modifiedStr);
orig = std::vector<u8>(origStr.begin(), origStr.end());
modified = std::vector<u8>(modifiedStr.begin(), modifiedStr.end());
diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.usd.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.usd.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\SdMenu.usd.diff");
// Japanese Files
// MnMaAll.dat
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.dat", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll-new.dat",
modifiedStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.dat", origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll-new.dat", modifiedStr);
orig = std::vector<u8>(origStr.begin(), origStr.end());
modified = std::vector<u8>(modifiedStr.begin(), modifiedStr.end());
diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.dat.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\MnMaAll.dat.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\MnMaAll.dat.diff");
// MnExtAll.dat
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.dat", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll-new.dat", modifiedStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.dat",
origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll-new.dat", modifiedStr);
orig = std::vector<u8>(origStr.begin(), origStr.end());
modified = std::vector<u8>(modifiedStr.begin(), modifiedStr.end());
diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.dat.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\CSS\\MnExtAll.dat.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\MnExtAll.dat.diff");
// SdMenu.dat
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.dat", origStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu-new.dat", modifiedStr);
File::ReadFileToString("C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.dat",
origStr);
File::ReadFileToString(
"C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu-new.dat", modifiedStr);
orig = std::vector<u8>(origStr.begin(), origStr.end());
modified = std::vector<u8>(modifiedStr.begin(), modifiedStr.end());
diff = processDiff(orig, modified);
File::WriteStringToFile(diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.dat.diff");
File::WriteStringToFile(
diff, "C:\\Users\\Jas\\Documents\\Melee\\Textures\\Slippi\\MainMenu\\SdMenu.dat.diff");
File::WriteStringToFile(diff, "C:\\Dolphin\\IshiiDev\\Sys\\GameFiles\\GALE01\\SdMenu.dat.diff");
// TEMP - Restore orig
@ -266,7 +282,8 @@ std::vector<u8> CEXISlippi::generateMetadata()
std::vector<char> dateTimeBuf(dateTimeStrLength);
strftime(&dateTimeBuf[0], dateTimeStrLength, "%FT%TZ", gmtime(&gameStartTime));
dateTimeBuf.pop_back(); // Removes the \0 from the back of string
metadata.insert(metadata.end(), { 'U', 7, 's', 't', 'a', 'r', 't', 'A', 't', 'S', 'U', (u8)dateTimeBuf.size() });
metadata.insert(metadata.end(),
{'U', 7, 's', 't', 'a', 'r', 't', 'A', 't', 'S', 'U', (u8)dateTimeBuf.size()});
metadata.insert(metadata.end(), dateTimeBuf.begin(), dateTimeBuf.end());
// Add game duration
@ -314,7 +331,8 @@ std::vector<u8> CEXISlippi::generateMetadata()
metadata.push_back('}'); // close names
// Add character element for this player
metadata.insert(metadata.end(), { 'U', 10, 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', 's', '{' });
metadata.insert(metadata.end(),
{'U', 10, 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', 's', '{'});
for (auto it2 = playerCharacterUsage.begin(); it2 != playerCharacterUsage.end(); ++it2)
{
metadata.push_back('U');
@ -333,8 +351,8 @@ std::vector<u8> CEXISlippi::generateMetadata()
metadata.push_back('}');
// Indicate this was played on dolphin
metadata.insert(metadata.end(),
{ 'U', 8, 'p', 'l', 'a', 'y', 'e', 'd', 'O', 'n', 'S', 'U', 7, 'd', 'o', 'l', 'p', 'h', 'i', 'n' });
metadata.insert(metadata.end(), {'U', 8, 'p', 'l', 'a', 'y', 'e', 'd', 'O', 'n',
'S', 'U', 7, 'd', 'o', 'l', 'p', 'h', 'i', 'n'});
metadata.push_back('}');
return metadata;
@ -600,7 +618,8 @@ void CEXISlippi::prepareGameInfo(u8* payload)
{
bkpPos += 1;
}
playbackSavestatePayload.insert(playbackSavestatePayload.end(), payload, payload + (bkpPos * 8 + 4));
playbackSavestatePayload.insert(playbackSavestatePayload.end(), payload,
payload + (bkpPos * 8 + 4));
Slippi::GameSettings* settings = m_current_game->GetSettings();
@ -732,187 +751,219 @@ void CEXISlippi::prepareGeckoList()
// TODO: How do I move this somewhere else?
// This contains all of the codes required to play legacy replays (UCF, PAL, Frz Stadium)
static std::vector<u8> defaultCodeList = {
0xC2, 0x0C, 0x9A, 0x44, 0x00, 0x00, 0x00, 0x2F, // #External/UCF + Arduino Toggle UI/UCF/UCF 0.74
// Dashback - Check for Toggle.asm
0xD0, 0x1F, 0x00, 0x2C, 0x88, 0x9F, 0x06, 0x18, 0x38, 0x62, 0xF2, 0x28, 0x7C, 0x63, 0x20, 0xAE, 0x2C, 0x03,
0x00, 0x01, 0x41, 0x82, 0x00, 0x14, 0x38, 0x62, 0xF2, 0x2C, 0x7C, 0x63, 0x20, 0xAE, 0x2C, 0x03, 0x00, 0x01,
0x40, 0x82, 0x01, 0x50, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81,
0x00, 0x08, 0x48, 0x00, 0x01, 0x21, 0x7F, 0xC8, 0x02, 0xA6, 0xC0, 0x3F, 0x08, 0x94, 0xC0, 0x5E, 0x00, 0x00,
0xFC, 0x01, 0x10, 0x40, 0x40, 0x82, 0x01, 0x18, 0x80, 0x8D, 0xAE, 0xB4, 0xC0, 0x3F, 0x06, 0x20, 0xFC, 0x20,
0x0A, 0x10, 0xC0, 0x44, 0x00, 0x3C, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x80, 0x01, 0x00, 0x88, 0x7F, 0x06, 0x70,
0x2C, 0x03, 0x00, 0x02, 0x40, 0x80, 0x00, 0xF4, 0x88, 0x7F, 0x22, 0x1F, 0x54, 0x60, 0x07, 0x39, 0x40, 0x82,
0x00, 0xE8, 0x3C, 0x60, 0x80, 0x4C, 0x60, 0x63, 0x1F, 0x78, 0x8B, 0xA3, 0x00, 0x01, 0x38, 0x7D, 0xFF, 0xFE,
0x88, 0x9F, 0x06, 0x18, 0x48, 0x00, 0x00, 0x8D, 0x7C, 0x7C, 0x1B, 0x78, 0x7F, 0xA3, 0xEB, 0x78, 0x88, 0x9F,
0x06, 0x18, 0x48, 0x00, 0x00, 0x7D, 0x7C, 0x7C, 0x18, 0x50, 0x7C, 0x63, 0x19, 0xD6, 0x2C, 0x03, 0x15, 0xF9,
0x40, 0x81, 0x00, 0xB0, 0x38, 0x00, 0x00, 0x01, 0x90, 0x1F, 0x23, 0x58, 0x90, 0x1F, 0x23, 0x40, 0x80, 0x9F,
0x00, 0x04, 0x2C, 0x04, 0x00, 0x0A, 0x40, 0xA2, 0x00, 0x98, 0x88, 0x7F, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x01,
0x3D, 0x80, 0x80, 0x03, 0x61, 0x8C, 0x41, 0x8C, 0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x2C, 0x03,
0x00, 0x00, 0x41, 0x82, 0x00, 0x78, 0x80, 0x83, 0x00, 0x2C, 0x80, 0x84, 0x1E, 0xCC, 0xC0, 0x3F, 0x00, 0x2C,
0xD0, 0x24, 0x00, 0x18, 0xC0, 0x5E, 0x00, 0x04, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x81, 0x00, 0x0C, 0x38, 0x60,
0x00, 0x80, 0x48, 0x00, 0x00, 0x08, 0x38, 0x60, 0x00, 0x7F, 0x98, 0x64, 0x00, 0x06, 0x48, 0x00, 0x00, 0x48,
0x7C, 0x85, 0x23, 0x78, 0x38, 0x63, 0xFF, 0xFF, 0x2C, 0x03, 0x00, 0x00, 0x40, 0x80, 0x00, 0x08, 0x38, 0x63,
0x00, 0x05, 0x3C, 0x80, 0x80, 0x46, 0x60, 0x84, 0xB1, 0x08, 0x1C, 0x63, 0x00, 0x30, 0x7C, 0x84, 0x1A, 0x14,
0x1C, 0x65, 0x00, 0x0C, 0x7C, 0x84, 0x1A, 0x14, 0x88, 0x64, 0x00, 0x02, 0x7C, 0x63, 0x07, 0x74, 0x4E, 0x80,
0x00, 0x20, 0x4E, 0x80, 0x00, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x81, 0x00, 0x08,
0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x09,
0x98, 0xA4, 0x00, 0x00, 0x00, 0x2B, // #External/UCF + Arduino Toggle UI/UCF/UCF
0xC2, 0x0C, 0x9A, 0x44, 0x00, 0x00, 0x00, 0x2F, // #External/UCF + Arduino Toggle UI/UCF/UCF
// 0.74 Dashback - Check for Toggle.asm
0xD0, 0x1F, 0x00, 0x2C, 0x88, 0x9F, 0x06, 0x18, 0x38, 0x62, 0xF2, 0x28, 0x7C, 0x63, 0x20,
0xAE, 0x2C, 0x03, 0x00, 0x01, 0x41, 0x82, 0x00, 0x14, 0x38, 0x62, 0xF2, 0x2C, 0x7C, 0x63,
0x20, 0xAE, 0x2C, 0x03, 0x00, 0x01, 0x40, 0x82, 0x01, 0x50, 0x7C, 0x08, 0x02, 0xA6, 0x90,
0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81, 0x00, 0x08, 0x48, 0x00, 0x01, 0x21,
0x7F, 0xC8, 0x02, 0xA6, 0xC0, 0x3F, 0x08, 0x94, 0xC0, 0x5E, 0x00, 0x00, 0xFC, 0x01, 0x10,
0x40, 0x40, 0x82, 0x01, 0x18, 0x80, 0x8D, 0xAE, 0xB4, 0xC0, 0x3F, 0x06, 0x20, 0xFC, 0x20,
0x0A, 0x10, 0xC0, 0x44, 0x00, 0x3C, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x80, 0x01, 0x00, 0x88,
0x7F, 0x06, 0x70, 0x2C, 0x03, 0x00, 0x02, 0x40, 0x80, 0x00, 0xF4, 0x88, 0x7F, 0x22, 0x1F,
0x54, 0x60, 0x07, 0x39, 0x40, 0x82, 0x00, 0xE8, 0x3C, 0x60, 0x80, 0x4C, 0x60, 0x63, 0x1F,
0x78, 0x8B, 0xA3, 0x00, 0x01, 0x38, 0x7D, 0xFF, 0xFE, 0x88, 0x9F, 0x06, 0x18, 0x48, 0x00,
0x00, 0x8D, 0x7C, 0x7C, 0x1B, 0x78, 0x7F, 0xA3, 0xEB, 0x78, 0x88, 0x9F, 0x06, 0x18, 0x48,
0x00, 0x00, 0x7D, 0x7C, 0x7C, 0x18, 0x50, 0x7C, 0x63, 0x19, 0xD6, 0x2C, 0x03, 0x15, 0xF9,
0x40, 0x81, 0x00, 0xB0, 0x38, 0x00, 0x00, 0x01, 0x90, 0x1F, 0x23, 0x58, 0x90, 0x1F, 0x23,
0x40, 0x80, 0x9F, 0x00, 0x04, 0x2C, 0x04, 0x00, 0x0A, 0x40, 0xA2, 0x00, 0x98, 0x88, 0x7F,
0x00, 0x0C, 0x38, 0x80, 0x00, 0x01, 0x3D, 0x80, 0x80, 0x03, 0x61, 0x8C, 0x41, 0x8C, 0x7D,
0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x78,
0x80, 0x83, 0x00, 0x2C, 0x80, 0x84, 0x1E, 0xCC, 0xC0, 0x3F, 0x00, 0x2C, 0xD0, 0x24, 0x00,
0x18, 0xC0, 0x5E, 0x00, 0x04, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x81, 0x00, 0x0C, 0x38, 0x60,
0x00, 0x80, 0x48, 0x00, 0x00, 0x08, 0x38, 0x60, 0x00, 0x7F, 0x98, 0x64, 0x00, 0x06, 0x48,
0x00, 0x00, 0x48, 0x7C, 0x85, 0x23, 0x78, 0x38, 0x63, 0xFF, 0xFF, 0x2C, 0x03, 0x00, 0x00,
0x40, 0x80, 0x00, 0x08, 0x38, 0x63, 0x00, 0x05, 0x3C, 0x80, 0x80, 0x46, 0x60, 0x84, 0xB1,
0x08, 0x1C, 0x63, 0x00, 0x30, 0x7C, 0x84, 0x1A, 0x14, 0x1C, 0x65, 0x00, 0x0C, 0x7C, 0x84,
0x1A, 0x14, 0x88, 0x64, 0x00, 0x02, 0x7C, 0x63, 0x07, 0x74, 0x4E, 0x80, 0x00, 0x20, 0x4E,
0x80, 0x00, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x81, 0x00, 0x08,
0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6, 0x00, 0x00, 0x00,
0x00, 0xC2, 0x09, 0x98, 0xA4, 0x00, 0x00, 0x00,
0x2B, // #External/UCF + Arduino Toggle UI/UCF/UCF
// 0.74 Shield Drop - Check for Toggle.asm
0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81, 0x00, 0x08, 0x7C, 0x7E,
0x1B, 0x78, 0x83, 0xFE, 0x00, 0x2C, 0x48, 0x00, 0x01, 0x01, 0x7F, 0xA8, 0x02, 0xA6, 0x88, 0x9F, 0x06, 0x18,
0x38, 0x62, 0xF2, 0x28, 0x7C, 0x63, 0x20, 0xAE, 0x2C, 0x03, 0x00, 0x01, 0x41, 0x82, 0x00, 0x14, 0x38, 0x62,
0xF2, 0x30, 0x7C, 0x63, 0x20, 0xAE, 0x2C, 0x03, 0x00, 0x01, 0x40, 0x82, 0x00, 0xF8, 0xC0, 0x3F, 0x06, 0x3C,
0x80, 0x6D, 0xAE, 0xB4, 0xC0, 0x03, 0x03, 0x14, 0xFC, 0x01, 0x00, 0x40, 0x40, 0x81, 0x00, 0xE4, 0xC0, 0x3F,
0x06, 0x20, 0x48, 0x00, 0x00, 0x71, 0xD0, 0x21, 0x00, 0x90, 0xC0, 0x3F, 0x06, 0x24, 0x48, 0x00, 0x00, 0x65,
0xC0, 0x41, 0x00, 0x90, 0xEC, 0x42, 0x00, 0xB2, 0xEC, 0x21, 0x00, 0x72, 0xEC, 0x21, 0x10, 0x2A, 0xC0, 0x5D,
0x00, 0x0C, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x80, 0x00, 0xB4, 0x88, 0x9F, 0x06, 0x70, 0x2C, 0x04, 0x00, 0x03,
0x40, 0x81, 0x00, 0xA8, 0xC0, 0x1D, 0x00, 0x10, 0xC0, 0x3F, 0x06, 0x24, 0xFC, 0x00, 0x08, 0x40, 0x40, 0x80,
0x00, 0x98, 0xBA, 0x81, 0x00, 0x08, 0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6,
0x80, 0x61, 0x00, 0x1C, 0x83, 0xE1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x18, 0x38, 0x63, 0x00, 0x08, 0x7C, 0x68,
0x03, 0xA6, 0x4E, 0x80, 0x00, 0x20, 0xFC, 0x00, 0x0A, 0x10, 0xC0, 0x3D, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x72,
0xC0, 0x3D, 0x00, 0x04, 0xEC, 0x00, 0x08, 0x28, 0xFC, 0x00, 0x00, 0x1E, 0xD8, 0x01, 0x00, 0x80, 0x80, 0x61,
0x00, 0x84, 0x38, 0x63, 0x00, 0x02, 0x3C, 0x00, 0x43, 0x30, 0xC8, 0x5D, 0x00, 0x14, 0x6C, 0x63, 0x80, 0x00,
0x90, 0x01, 0x00, 0x80, 0x90, 0x61, 0x00, 0x84, 0xC8, 0x21, 0x00, 0x80, 0xEC, 0x01, 0x10, 0x28, 0xC0, 0x3D,
0x00, 0x00, 0xEC, 0x20, 0x08, 0x24, 0x4E, 0x80, 0x00, 0x20, 0x4E, 0x80, 0x00, 0x21, 0x42, 0xA0, 0x00, 0x00,
0x37, 0x27, 0x00, 0x00, 0x43, 0x30, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xBF, 0x4C, 0xCC, 0xCD, 0x43, 0x30,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xC3, 0xF3, 0x78, 0x7F, 0xE4, 0xFB, 0x78, 0xBA, 0x81, 0x00, 0x08,
0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC2, 0x16, 0xE7, 0x50, 0x00, 0x00, 0x00,
0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81, 0x00,
0x08, 0x7C, 0x7E, 0x1B, 0x78, 0x83, 0xFE, 0x00, 0x2C, 0x48, 0x00, 0x01, 0x01, 0x7F, 0xA8,
0x02, 0xA6, 0x88, 0x9F, 0x06, 0x18, 0x38, 0x62, 0xF2, 0x28, 0x7C, 0x63, 0x20, 0xAE, 0x2C,
0x03, 0x00, 0x01, 0x41, 0x82, 0x00, 0x14, 0x38, 0x62, 0xF2, 0x30, 0x7C, 0x63, 0x20, 0xAE,
0x2C, 0x03, 0x00, 0x01, 0x40, 0x82, 0x00, 0xF8, 0xC0, 0x3F, 0x06, 0x3C, 0x80, 0x6D, 0xAE,
0xB4, 0xC0, 0x03, 0x03, 0x14, 0xFC, 0x01, 0x00, 0x40, 0x40, 0x81, 0x00, 0xE4, 0xC0, 0x3F,
0x06, 0x20, 0x48, 0x00, 0x00, 0x71, 0xD0, 0x21, 0x00, 0x90, 0xC0, 0x3F, 0x06, 0x24, 0x48,
0x00, 0x00, 0x65, 0xC0, 0x41, 0x00, 0x90, 0xEC, 0x42, 0x00, 0xB2, 0xEC, 0x21, 0x00, 0x72,
0xEC, 0x21, 0x10, 0x2A, 0xC0, 0x5D, 0x00, 0x0C, 0xFC, 0x01, 0x10, 0x40, 0x41, 0x80, 0x00,
0xB4, 0x88, 0x9F, 0x06, 0x70, 0x2C, 0x04, 0x00, 0x03, 0x40, 0x81, 0x00, 0xA8, 0xC0, 0x1D,
0x00, 0x10, 0xC0, 0x3F, 0x06, 0x24, 0xFC, 0x00, 0x08, 0x40, 0x40, 0x80, 0x00, 0x98, 0xBA,
0x81, 0x00, 0x08, 0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6,
0x80, 0x61, 0x00, 0x1C, 0x83, 0xE1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x18, 0x38, 0x63, 0x00,
0x08, 0x7C, 0x68, 0x03, 0xA6, 0x4E, 0x80, 0x00, 0x20, 0xFC, 0x00, 0x0A, 0x10, 0xC0, 0x3D,
0x00, 0x00, 0xEC, 0x00, 0x00, 0x72, 0xC0, 0x3D, 0x00, 0x04, 0xEC, 0x00, 0x08, 0x28, 0xFC,
0x00, 0x00, 0x1E, 0xD8, 0x01, 0x00, 0x80, 0x80, 0x61, 0x00, 0x84, 0x38, 0x63, 0x00, 0x02,
0x3C, 0x00, 0x43, 0x30, 0xC8, 0x5D, 0x00, 0x14, 0x6C, 0x63, 0x80, 0x00, 0x90, 0x01, 0x00,
0x80, 0x90, 0x61, 0x00, 0x84, 0xC8, 0x21, 0x00, 0x80, 0xEC, 0x01, 0x10, 0x28, 0xC0, 0x3D,
0x00, 0x00, 0xEC, 0x20, 0x08, 0x24, 0x4E, 0x80, 0x00, 0x20, 0x4E, 0x80, 0x00, 0x21, 0x42,
0xA0, 0x00, 0x00, 0x37, 0x27, 0x00, 0x00, 0x43, 0x30, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
0xBF, 0x4C, 0xCC, 0xCD, 0x43, 0x30, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xC3, 0xF3,
0x78, 0x7F, 0xE4, 0xFB, 0x78, 0xBA, 0x81, 0x00, 0x08, 0x80, 0x01, 0x00, 0xB4, 0x38, 0x21,
0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2,
0x16, 0xE7, 0x50, 0x00, 0x00, 0x00,
0x33, // #Common/StaticPatches/ToggledStaticOverwrites.asm
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x14, 0x48, 0x00, 0x00, 0x75, 0x7C, 0x68,
0x02, 0xA6, 0x48, 0x00, 0x01, 0x3D, 0x48, 0x00, 0x00, 0x14, 0x48, 0x00, 0x00, 0x95, 0x7C, 0x68, 0x02, 0xA6,
0x48, 0x00, 0x01, 0x2D, 0x48, 0x00, 0x00, 0x04, 0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82,
0x00, 0x14, 0x48, 0x00, 0x00, 0xB9, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x11, 0x48, 0x00, 0x00, 0x10,
0x48, 0x00, 0x00, 0xC9, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x01, 0x88, 0x62, 0xF2, 0x3C, 0x2C, 0x03,
0x00, 0x00, 0x41, 0x82, 0x00, 0x14, 0x48, 0x00, 0x00, 0xD1, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x00, 0xE9,
0x48, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xD1, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x00, 0xD9, 0x48, 0x00,
0x00, 0xF4, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x3C, 0xE4, 0xD4, 0x00, 0x24, 0x04, 0x64, 0x80, 0x07, 0x96, 0xE0,
0x60, 0x00, 0x00, 0x00, 0x80, 0x2B, 0x7E, 0x54, 0x48, 0x00, 0x00, 0x88, 0x80, 0x2B, 0x80, 0x8C, 0x48, 0x00,
0x00, 0x84, 0x80, 0x12, 0x39, 0xA8, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21,
0x80, 0x3C, 0xE4, 0xD4, 0x00, 0x20, 0x00, 0x00, 0x80, 0x07, 0x96, 0xE0, 0x3A, 0x40, 0x00, 0x01, 0x80, 0x2B,
0x7E, 0x54, 0x88, 0x7F, 0x22, 0x40, 0x80, 0x2B, 0x80, 0x8C, 0x2C, 0x03, 0x00, 0x02, 0x80, 0x10, 0xFC, 0x48,
0x90, 0x05, 0x21, 0xDC, 0x80, 0x10, 0xFB, 0x68, 0x90, 0x05, 0x21, 0xDC, 0x80, 0x12, 0x39, 0xA8, 0x90, 0x1F,
0x1A, 0x5C, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x46, 0x10, 0x48, 0x00, 0x00, 0x4C,
0x80, 0x1D, 0x47, 0x24, 0x48, 0x00, 0x00, 0x3C, 0x80, 0x1D, 0x46, 0x0C, 0x80, 0x9F, 0x00, 0xEC, 0xFF, 0xFF,
0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x46, 0x10, 0x38, 0x83, 0x7F, 0x9C, 0x80, 0x1D, 0x47, 0x24,
0x88, 0x1B, 0x00, 0xC4, 0x80, 0x1D, 0x46, 0x0C, 0x3C, 0x60, 0x80, 0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80,
0x00, 0x21, 0x80, 0x1D, 0x45, 0xFC, 0x48, 0x00, 0x09, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21,
0x80, 0x1D, 0x45, 0xFC, 0x40, 0x80, 0x09, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0x38, 0xA3, 0xFF, 0xFC, 0x84, 0x65,
0x00, 0x04, 0x2C, 0x03, 0xFF, 0xFF, 0x41, 0x82, 0x00, 0x10, 0x84, 0x85, 0x00, 0x04, 0x90, 0x83, 0x00, 0x00,
0x4B, 0xFF, 0xFF, 0xEC, 0x4E, 0x80, 0x00, 0x20, 0x3C, 0x60, 0x80, 0x00, 0x3C, 0x80, 0x00, 0x3B, 0x60, 0x84,
0x72, 0x2C, 0x3D, 0x80, 0x80, 0x32, 0x61, 0x8C, 0x8F, 0x50, 0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21,
0x3C, 0x60, 0x80, 0x17, 0x3C, 0x80, 0x80, 0x17, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x1D, 0x14, 0xC8, 0x00, 0x00,
0x00, 0x04, // #Common/Preload Stadium
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x14, 0x48, 0x00, 0x00,
0x75, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x3D, 0x48, 0x00, 0x00, 0x14, 0x48, 0x00,
0x00, 0x95, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x2D, 0x48, 0x00, 0x00, 0x04, 0x88,
0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x14, 0x48, 0x00, 0x00, 0xB9,
0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x11, 0x48, 0x00, 0x00, 0x10, 0x48, 0x00, 0x00,
0xC9, 0x7C, 0x68, 0x02, 0xA6, 0x48, 0x00, 0x01, 0x01, 0x88, 0x62, 0xF2, 0x3C, 0x2C, 0x03,
0x00, 0x00, 0x41, 0x82, 0x00, 0x14, 0x48, 0x00, 0x00, 0xD1, 0x7C, 0x68, 0x02, 0xA6, 0x48,
0x00, 0x00, 0xE9, 0x48, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xD1, 0x7C, 0x68, 0x02, 0xA6,
0x48, 0x00, 0x00, 0xD9, 0x48, 0x00, 0x00, 0xF4, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x3C, 0xE4,
0xD4, 0x00, 0x24, 0x04, 0x64, 0x80, 0x07, 0x96, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x80, 0x2B,
0x7E, 0x54, 0x48, 0x00, 0x00, 0x88, 0x80, 0x2B, 0x80, 0x8C, 0x48, 0x00, 0x00, 0x84, 0x80,
0x12, 0x39, 0xA8, 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21,
0x80, 0x3C, 0xE4, 0xD4, 0x00, 0x20, 0x00, 0x00, 0x80, 0x07, 0x96, 0xE0, 0x3A, 0x40, 0x00,
0x01, 0x80, 0x2B, 0x7E, 0x54, 0x88, 0x7F, 0x22, 0x40, 0x80, 0x2B, 0x80, 0x8C, 0x2C, 0x03,
0x00, 0x02, 0x80, 0x10, 0xFC, 0x48, 0x90, 0x05, 0x21, 0xDC, 0x80, 0x10, 0xFB, 0x68, 0x90,
0x05, 0x21, 0xDC, 0x80, 0x12, 0x39, 0xA8, 0x90, 0x1F, 0x1A, 0x5C, 0xFF, 0xFF, 0xFF, 0xFF,
0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x46, 0x10, 0x48, 0x00, 0x00, 0x4C, 0x80, 0x1D, 0x47,
0x24, 0x48, 0x00, 0x00, 0x3C, 0x80, 0x1D, 0x46, 0x0C, 0x80, 0x9F, 0x00, 0xEC, 0xFF, 0xFF,
0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x46, 0x10, 0x38, 0x83, 0x7F, 0x9C, 0x80,
0x1D, 0x47, 0x24, 0x88, 0x1B, 0x00, 0xC4, 0x80, 0x1D, 0x46, 0x0C, 0x3C, 0x60, 0x80, 0x3B,
0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x45, 0xFC, 0x48, 0x00, 0x09,
0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x80, 0x00, 0x21, 0x80, 0x1D, 0x45, 0xFC, 0x40, 0x80,
0x09, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0x38, 0xA3, 0xFF, 0xFC, 0x84, 0x65, 0x00, 0x04, 0x2C,
0x03, 0xFF, 0xFF, 0x41, 0x82, 0x00, 0x10, 0x84, 0x85, 0x00, 0x04, 0x90, 0x83, 0x00, 0x00,
0x4B, 0xFF, 0xFF, 0xEC, 0x4E, 0x80, 0x00, 0x20, 0x3C, 0x60, 0x80, 0x00, 0x3C, 0x80, 0x00,
0x3B, 0x60, 0x84, 0x72, 0x2C, 0x3D, 0x80, 0x80, 0x32, 0x61, 0x8C, 0x8F, 0x50, 0x7D, 0x89,
0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x3C, 0x60, 0x80, 0x17, 0x3C, 0x80, 0x80, 0x17, 0x00,
0x00, 0x00, 0x00, 0xC2, 0x1D, 0x14, 0xC8, 0x00, 0x00, 0x00,
0x04, // #Common/Preload Stadium
// Transformations/Handlers/Init
// isLoaded Bool.asm
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0C, 0x38, 0x60, 0x00, 0x00, 0x98, 0x7F,
0x00, 0xF0, 0x3B, 0xA0, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x1D, 0x45, 0xEC,
0x00, 0x00, 0x00, 0x1B, // #Common/Preload Stadium
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0C, 0x38, 0x60, 0x00,
0x00, 0x98, 0x7F, 0x00, 0xF0, 0x3B, 0xA0, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC2, 0x1D, 0x45, 0xEC, 0x00, 0x00, 0x00, 0x1B, // #Common/Preload Stadium
// Transformations/Handlers/Load
// Transformation.asm
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0xC4, 0x88, 0x7F, 0x00, 0xF0, 0x2C, 0x03,
0x00, 0x00, 0x40, 0x82, 0x00, 0xB8, 0x38, 0x60, 0x00, 0x04, 0x3D, 0x80, 0x80, 0x38, 0x61, 0x8C, 0x05, 0x80,
0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x54, 0x60, 0x10, 0x3A, 0xA8, 0x7F, 0x00, 0xE2, 0x3C, 0x80,
0x80, 0x3B, 0x60, 0x84, 0x7F, 0x9C, 0x7C, 0x84, 0x00, 0x2E, 0x7C, 0x03, 0x20, 0x00, 0x41, 0x82, 0xFF, 0xD4,
0x90, 0x9F, 0x00, 0xEC, 0x2C, 0x04, 0x00, 0x03, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x00, 0x48, 0x00,
0x00, 0x34, 0x2C, 0x04, 0x00, 0x04, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x01, 0x48, 0x00, 0x00, 0x24,
0x2C, 0x04, 0x00, 0x09, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x02, 0x48, 0x00, 0x00, 0x14, 0x2C, 0x04,
0x00, 0x06, 0x40, 0x82, 0x00, 0x00, 0x38, 0x80, 0x00, 0x03, 0x48, 0x00, 0x00, 0x04, 0x3C, 0x60, 0x80, 0x3E,
0x60, 0x63, 0x12, 0x48, 0x54, 0x80, 0x10, 0x3A, 0x7C, 0x63, 0x02, 0x14, 0x80, 0x63, 0x03, 0xD8, 0x80, 0x9F,
0x00, 0xCC, 0x38, 0xBF, 0x00, 0xC8, 0x3C, 0xC0, 0x80, 0x1D, 0x60, 0xC6, 0x42, 0x20, 0x38, 0xE0, 0x00, 0x00,
0x3D, 0x80, 0x80, 0x01, 0x61, 0x8C, 0x65, 0x80, 0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x38, 0x60,
0x00, 0x01, 0x98, 0x7F, 0x00, 0xF0, 0x80, 0x7F, 0x00, 0xD8, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC2, 0x1D, 0x4F, 0x14, 0x00, 0x00, 0x00, 0x04, // #Common/Preload
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0xC4, 0x88, 0x7F, 0x00,
0xF0, 0x2C, 0x03, 0x00, 0x00, 0x40, 0x82, 0x00, 0xB8, 0x38, 0x60, 0x00, 0x04, 0x3D, 0x80,
0x80, 0x38, 0x61, 0x8C, 0x05, 0x80, 0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x54,
0x60, 0x10, 0x3A, 0xA8, 0x7F, 0x00, 0xE2, 0x3C, 0x80, 0x80, 0x3B, 0x60, 0x84, 0x7F, 0x9C,
0x7C, 0x84, 0x00, 0x2E, 0x7C, 0x03, 0x20, 0x00, 0x41, 0x82, 0xFF, 0xD4, 0x90, 0x9F, 0x00,
0xEC, 0x2C, 0x04, 0x00, 0x03, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x00, 0x48, 0x00,
0x00, 0x34, 0x2C, 0x04, 0x00, 0x04, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x01, 0x48,
0x00, 0x00, 0x24, 0x2C, 0x04, 0x00, 0x09, 0x40, 0x82, 0x00, 0x0C, 0x38, 0x80, 0x00, 0x02,
0x48, 0x00, 0x00, 0x14, 0x2C, 0x04, 0x00, 0x06, 0x40, 0x82, 0x00, 0x00, 0x38, 0x80, 0x00,
0x03, 0x48, 0x00, 0x00, 0x04, 0x3C, 0x60, 0x80, 0x3E, 0x60, 0x63, 0x12, 0x48, 0x54, 0x80,
0x10, 0x3A, 0x7C, 0x63, 0x02, 0x14, 0x80, 0x63, 0x03, 0xD8, 0x80, 0x9F, 0x00, 0xCC, 0x38,
0xBF, 0x00, 0xC8, 0x3C, 0xC0, 0x80, 0x1D, 0x60, 0xC6, 0x42, 0x20, 0x38, 0xE0, 0x00, 0x00,
0x3D, 0x80, 0x80, 0x01, 0x61, 0x8C, 0x65, 0x80, 0x7D, 0x89, 0x03, 0xA6, 0x4E, 0x80, 0x04,
0x21, 0x38, 0x60, 0x00, 0x01, 0x98, 0x7F, 0x00, 0xF0, 0x80, 0x7F, 0x00, 0xD8, 0x60, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x1D, 0x4F, 0x14, 0x00, 0x00, 0x00,
0x04, // #Common/Preload
// Stadium
// Transformations/Handlers/Reset
// isLoaded.asm
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0C, 0x38, 0x60, 0x00, 0x00, 0x98, 0x7F,
0x00, 0xF0, 0x80, 0x6D, 0xB2, 0xD8, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x06, 0x8F, 0x30,
0x00, 0x00, 0x00, 0x9D, // #Common/PAL/Handlers/Character DAT
// Patcher.asm
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x04, 0xD4, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01,
0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81, 0x00, 0x08, 0x83, 0xFE, 0x01, 0x0C, 0x83, 0xFF, 0x00, 0x08,
0x3B, 0xFF, 0xFF, 0xE0, 0x80, 0x7D, 0x00, 0x00, 0x2C, 0x03, 0x00, 0x1B, 0x40, 0x80, 0x04, 0x9C, 0x48, 0x00,
0x00, 0x71, 0x48, 0x00, 0x00, 0xA9, 0x48, 0x00, 0x00, 0xB9, 0x48, 0x00, 0x01, 0x51, 0x48, 0x00, 0x01, 0x79,
0x48, 0x00, 0x01, 0x79, 0x48, 0x00, 0x02, 0x29, 0x48, 0x00, 0x02, 0x39, 0x48, 0x00, 0x02, 0x81, 0x48, 0x00,
0x02, 0xF9, 0x48, 0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x11,
0x48, 0x00, 0x03, 0x21, 0x48, 0x00, 0x03, 0x21, 0x48, 0x00, 0x03, 0x89, 0x48, 0x00, 0x03, 0x89, 0x48, 0x00,
0x03, 0x91, 0x48, 0x00, 0x03, 0x91, 0x48, 0x00, 0x03, 0xA9, 0x48, 0x00, 0x03, 0xA9, 0x48, 0x00, 0x03, 0xB9,
0x48, 0x00, 0x03, 0xB9, 0x48, 0x00, 0x03, 0xC9, 0x48, 0x00, 0x03, 0xC9, 0x48, 0x00, 0x03, 0xC9, 0x48, 0x00,
0x04, 0x29, 0x7C, 0x88, 0x02, 0xA6, 0x1C, 0x63, 0x00, 0x04, 0x7C, 0x84, 0x1A, 0x14, 0x80, 0xA4, 0x00, 0x00,
0x54, 0xA5, 0x01, 0xBA, 0x7C, 0xA4, 0x2A, 0x14, 0x80, 0x65, 0x00, 0x00, 0x80, 0x85, 0x00, 0x04, 0x2C, 0x03,
0x00, 0xFF, 0x41, 0x82, 0x00, 0x14, 0x7C, 0x63, 0xFA, 0x14, 0x90, 0x83, 0x00, 0x00, 0x38, 0xA5, 0x00, 0x08,
0x4B, 0xFF, 0xFF, 0xE4, 0x48, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x33, 0x44, 0x3F, 0x54, 0x7A, 0xE1, 0x00, 0x00,
0x33, 0x60, 0x42, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x37, 0x9C, 0x42, 0x92, 0x00, 0x00,
0x00, 0x00, 0x39, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x0C, 0x40, 0x86, 0x66, 0x66, 0x00, 0x00,
0x39, 0x10, 0x3D, 0xEA, 0x0E, 0xA1, 0x00, 0x00, 0x39, 0x28, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x04,
0x2C, 0x01, 0x48, 0x0C, 0x00, 0x00, 0x47, 0x20, 0x1B, 0x96, 0x80, 0x13, 0x00, 0x00, 0x47, 0x34, 0x1B, 0x96,
0x80, 0x13, 0x00, 0x00, 0x47, 0x3C, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x4A, 0x40, 0x2C, 0x00, 0x68, 0x11,
0x00, 0x00, 0x4A, 0x4C, 0x28, 0x1B, 0x00, 0x13, 0x00, 0x00, 0x4A, 0x50, 0x0D, 0x00, 0x01, 0x0B, 0x00, 0x00,
0x4A, 0x54, 0x2C, 0x80, 0x68, 0x11, 0x00, 0x00, 0x4A, 0x60, 0x28, 0x1B, 0x00, 0x13, 0x00, 0x00, 0x4A, 0x64,
0x0D, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x4B, 0x24, 0x2C, 0x00, 0x68, 0x0D, 0x00, 0x00, 0x4B, 0x30, 0x0F, 0x10,
0x40, 0x13, 0x00, 0x00, 0x4B, 0x38, 0x2C, 0x80, 0x38, 0x0D, 0x00, 0x00, 0x4B, 0x44, 0x0F, 0x10, 0x40, 0x13,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x38, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x4E, 0xF8, 0x2C, 0x00,
0x38, 0x03, 0x00, 0x00, 0x4F, 0x08, 0x0F, 0x80, 0x00, 0x0B, 0x00, 0x00, 0x4F, 0x0C, 0x2C, 0x80, 0x20, 0x03,
0x00, 0x00, 0x4F, 0x1C, 0x0F, 0x80, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x4D, 0x10, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x70, 0x42, 0x94, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xD4,
0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xE0, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x83, 0xAC, 0x2C, 0x00,
0x00, 0x09, 0x00, 0x00, 0x83, 0xB8, 0x34, 0x8C, 0x80, 0x11, 0x00, 0x00, 0x84, 0x00, 0x34, 0x8C, 0x80, 0x11,
0x00, 0x00, 0x84, 0x30, 0x05, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x84, 0x38, 0x04, 0x1A, 0x05, 0x00, 0x00, 0x00,
0x84, 0x44, 0x05, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x84, 0xDC, 0x05, 0x78, 0x05, 0x78, 0x00, 0x00, 0x85, 0xB8,
0x10, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x85, 0xC0, 0x03, 0xE8, 0x01, 0xF4, 0x00, 0x00, 0x85, 0xCC, 0x10, 0x00,
0x01, 0x0B, 0x00, 0x00, 0x85, 0xD4, 0x03, 0x84, 0x03, 0xE8, 0x00, 0x00, 0x85, 0xE0, 0x10, 0x00, 0x01, 0x0B,
0x00, 0x00, 0x88, 0x18, 0x0B, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x88, 0x2C, 0x0B, 0x00, 0x01, 0x0B, 0x00, 0x00,
0x88, 0xF8, 0x04, 0x1A, 0x0B, 0xB8, 0x00, 0x00, 0x89, 0x3C, 0x04, 0x1A, 0x0B, 0xB8, 0x00, 0x00, 0x89, 0x80,
0x04, 0x1A, 0x0B, 0xB8, 0x00, 0x00, 0x89, 0xE0, 0x04, 0xFE, 0xF7, 0x04, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x36, 0xCC, 0x42, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x37, 0xC4, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x34, 0x68, 0x3F, 0x66, 0x66, 0x66, 0x00, 0x00, 0x39, 0xD8, 0x44, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x3A, 0x44, 0xB4, 0x99, 0x00, 0x11, 0x00, 0x00, 0x3A, 0x48, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3A, 0x58,
0xB4, 0x99, 0x00, 0x11, 0x00, 0x00, 0x3A, 0x5C, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3A, 0x6C, 0xB4, 0x99,
0x00, 0x11, 0x00, 0x00, 0x3A, 0x70, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3B, 0x30, 0x44, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x45, 0xC8, 0x2C, 0x01, 0x50, 0x10, 0x00, 0x00, 0x45, 0xD4, 0x2D, 0x19,
0x80, 0x13, 0x00, 0x00, 0x45, 0xDC, 0x2C, 0x80, 0xB0, 0x10, 0x00, 0x00, 0x45, 0xE8, 0x2D, 0x19, 0x80, 0x13,
0x00, 0x00, 0x49, 0xC4, 0x2C, 0x00, 0x68, 0x0A, 0x00, 0x00, 0x49, 0xD0, 0x28, 0x1B, 0x80, 0x13, 0x00, 0x00,
0x49, 0xD8, 0x2C, 0x80, 0x78, 0x0A, 0x00, 0x00, 0x49, 0xE4, 0x28, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x49, 0xF0,
0x2C, 0x00, 0x68, 0x08, 0x00, 0x00, 0x49, 0xFC, 0x23, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x4A, 0x04, 0x2C, 0x80,
0x78, 0x08, 0x00, 0x00, 0x4A, 0x10, 0x23, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x5C, 0x98, 0x1E, 0x0C, 0x80, 0x80,
0x00, 0x00, 0x5C, 0xF4, 0xB4, 0x80, 0x0C, 0x90, 0x00, 0x00, 0x5D, 0x08, 0xB4, 0x80, 0x0C, 0x90, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x3A, 0x1C, 0xB4, 0x94, 0x00, 0x13, 0x00, 0x00, 0x3A, 0x64, 0x2C, 0x00, 0x00, 0x15,
0x00, 0x00, 0x3A, 0x70, 0xB4, 0x92, 0x80, 0x13, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x64, 0x7C, 0xB4, 0x9A, 0x40, 0x17, 0x00, 0x00, 0x64, 0x80,
0x64, 0x00, 0x10, 0x97, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x33, 0xE4, 0x42, 0xDE,
0x00, 0x00, 0x00, 0x00, 0x45, 0x28, 0x2C, 0x01, 0x30, 0x11, 0x00, 0x00, 0x45, 0x34, 0xB4, 0x98, 0x80, 0x13,
0x00, 0x00, 0x45, 0x3C, 0x2C, 0x81, 0x30, 0x11, 0x00, 0x00, 0x45, 0x48, 0xB4, 0x98, 0x80, 0x13, 0x00, 0x00,
0x45, 0x50, 0x2D, 0x00, 0x20, 0x11, 0x00, 0x00, 0x45, 0x5C, 0xB4, 0x98, 0x80, 0x13, 0x00, 0x00, 0x45, 0xF8,
0x2C, 0x01, 0x30, 0x0F, 0x00, 0x00, 0x46, 0x08, 0x0F, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x46, 0x0C, 0x2C, 0x81,
0x28, 0x0F, 0x00, 0x00, 0x46, 0x1C, 0x0F, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x4A, 0xEC, 0x2C, 0x00, 0x70, 0x03,
0x00, 0x00, 0x4B, 0x00, 0x2C, 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x48, 0x5C, 0x2C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x37, 0xB0,
0x3F, 0x59, 0x99, 0x9A, 0x00, 0x00, 0x37, 0xCC, 0x42, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x55, 0x20, 0x87, 0x11,
0x80, 0x13, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3B, 0x8C, 0x44, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x3D, 0x0C, 0x44, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x50, 0xE4, 0xB4, 0x99, 0x00, 0x13, 0x00, 0x00, 0x50, 0xF8, 0xB4, 0x99, 0x00, 0x13, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x4E, 0xB0, 0x02, 0xBC, 0xFF, 0x38, 0x00, 0x00,
0x4E, 0xBC, 0x14, 0x00, 0x01, 0x23, 0x00, 0x00, 0x4E, 0xC4, 0x03, 0x84, 0x01, 0xF4, 0x00, 0x00, 0x4E, 0xD0,
0x14, 0x00, 0x01, 0x23, 0x00, 0x00, 0x4E, 0xD8, 0x04, 0x4C, 0x04, 0xB0, 0x00, 0x00, 0x4E, 0xE4, 0x14, 0x00,
0x01, 0x23, 0x00, 0x00, 0x50, 0x5C, 0x2C, 0x00, 0x68, 0x15, 0x00, 0x00, 0x50, 0x6C, 0x14, 0x08, 0x01, 0x23,
0x00, 0x00, 0x50, 0x70, 0x2C, 0x80, 0x60, 0x15, 0x00, 0x00, 0x50, 0x80, 0x14, 0x08, 0x01, 0x23, 0x00, 0x00,
0x50, 0x84, 0x2D, 0x00, 0x20, 0x15, 0x00, 0x00, 0x50, 0x94, 0x14, 0x08, 0x01, 0x23, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xBA, 0x81, 0x00, 0x08, 0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08,
0x03, 0xA6, 0x3C, 0x60, 0x80, 0x3C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x2F, 0x9A, 0x3C,
0x88, 0x62, 0xF2, 0x38, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0C, 0x38, 0x60, 0x00,
0x00, 0x98, 0x7F, 0x00, 0xF0, 0x80, 0x6D, 0xB2, 0xD8, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC2, 0x06, 0x8F, 0x30, 0x00, 0x00, 0x00, 0x9D, // #Common/PAL/Handlers/Character
// DAT Patcher.asm
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x04, 0xD4, 0x7C, 0x08, 0x02,
0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x50, 0xBE, 0x81, 0x00, 0x08, 0x83, 0xFE,
0x01, 0x0C, 0x83, 0xFF, 0x00, 0x08, 0x3B, 0xFF, 0xFF, 0xE0, 0x80, 0x7D, 0x00, 0x00, 0x2C,
0x03, 0x00, 0x1B, 0x40, 0x80, 0x04, 0x9C, 0x48, 0x00, 0x00, 0x71, 0x48, 0x00, 0x00, 0xA9,
0x48, 0x00, 0x00, 0xB9, 0x48, 0x00, 0x01, 0x51, 0x48, 0x00, 0x01, 0x79, 0x48, 0x00, 0x01,
0x79, 0x48, 0x00, 0x02, 0x29, 0x48, 0x00, 0x02, 0x39, 0x48, 0x00, 0x02, 0x81, 0x48, 0x00,
0x02, 0xF9, 0x48, 0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x11, 0x48,
0x00, 0x03, 0x11, 0x48, 0x00, 0x03, 0x21, 0x48, 0x00, 0x03, 0x21, 0x48, 0x00, 0x03, 0x89,
0x48, 0x00, 0x03, 0x89, 0x48, 0x00, 0x03, 0x91, 0x48, 0x00, 0x03, 0x91, 0x48, 0x00, 0x03,
0xA9, 0x48, 0x00, 0x03, 0xA9, 0x48, 0x00, 0x03, 0xB9, 0x48, 0x00, 0x03, 0xB9, 0x48, 0x00,
0x03, 0xC9, 0x48, 0x00, 0x03, 0xC9, 0x48, 0x00, 0x03, 0xC9, 0x48, 0x00, 0x04, 0x29, 0x7C,
0x88, 0x02, 0xA6, 0x1C, 0x63, 0x00, 0x04, 0x7C, 0x84, 0x1A, 0x14, 0x80, 0xA4, 0x00, 0x00,
0x54, 0xA5, 0x01, 0xBA, 0x7C, 0xA4, 0x2A, 0x14, 0x80, 0x65, 0x00, 0x00, 0x80, 0x85, 0x00,
0x04, 0x2C, 0x03, 0x00, 0xFF, 0x41, 0x82, 0x00, 0x14, 0x7C, 0x63, 0xFA, 0x14, 0x90, 0x83,
0x00, 0x00, 0x38, 0xA5, 0x00, 0x08, 0x4B, 0xFF, 0xFF, 0xE4, 0x48, 0x00, 0x03, 0xF0, 0x00,
0x00, 0x33, 0x44, 0x3F, 0x54, 0x7A, 0xE1, 0x00, 0x00, 0x33, 0x60, 0x42, 0xC4, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x37, 0x9C, 0x42, 0x92, 0x00, 0x00, 0x00, 0x00, 0x39,
0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x0C, 0x40, 0x86, 0x66, 0x66, 0x00, 0x00,
0x39, 0x10, 0x3D, 0xEA, 0x0E, 0xA1, 0x00, 0x00, 0x39, 0x28, 0x41, 0xA0, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x04, 0x2C, 0x01, 0x48, 0x0C, 0x00, 0x00, 0x47, 0x20, 0x1B, 0x96, 0x80, 0x13,
0x00, 0x00, 0x47, 0x34, 0x1B, 0x96, 0x80, 0x13, 0x00, 0x00, 0x47, 0x3C, 0x04, 0x00, 0x00,
0x09, 0x00, 0x00, 0x4A, 0x40, 0x2C, 0x00, 0x68, 0x11, 0x00, 0x00, 0x4A, 0x4C, 0x28, 0x1B,
0x00, 0x13, 0x00, 0x00, 0x4A, 0x50, 0x0D, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x4A, 0x54, 0x2C,
0x80, 0x68, 0x11, 0x00, 0x00, 0x4A, 0x60, 0x28, 0x1B, 0x00, 0x13, 0x00, 0x00, 0x4A, 0x64,
0x0D, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x4B, 0x24, 0x2C, 0x00, 0x68, 0x0D, 0x00, 0x00, 0x4B,
0x30, 0x0F, 0x10, 0x40, 0x13, 0x00, 0x00, 0x4B, 0x38, 0x2C, 0x80, 0x38, 0x0D, 0x00, 0x00,
0x4B, 0x44, 0x0F, 0x10, 0x40, 0x13, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x38, 0x0C, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x4E, 0xF8, 0x2C, 0x00, 0x38, 0x03, 0x00, 0x00, 0x4F, 0x08,
0x0F, 0x80, 0x00, 0x0B, 0x00, 0x00, 0x4F, 0x0C, 0x2C, 0x80, 0x20, 0x03, 0x00, 0x00, 0x4F,
0x1C, 0x0F, 0x80, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x4D, 0x10, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x70, 0x42, 0x94, 0x00, 0x00, 0x00,
0x00, 0x4D, 0xD4, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0xE0, 0x41, 0x90, 0x00, 0x00,
0x00, 0x00, 0x83, 0xAC, 0x2C, 0x00, 0x00, 0x09, 0x00, 0x00, 0x83, 0xB8, 0x34, 0x8C, 0x80,
0x11, 0x00, 0x00, 0x84, 0x00, 0x34, 0x8C, 0x80, 0x11, 0x00, 0x00, 0x84, 0x30, 0x05, 0x00,
0x00, 0x8B, 0x00, 0x00, 0x84, 0x38, 0x04, 0x1A, 0x05, 0x00, 0x00, 0x00, 0x84, 0x44, 0x05,
0x00, 0x00, 0x8B, 0x00, 0x00, 0x84, 0xDC, 0x05, 0x78, 0x05, 0x78, 0x00, 0x00, 0x85, 0xB8,
0x10, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x85, 0xC0, 0x03, 0xE8, 0x01, 0xF4, 0x00, 0x00, 0x85,
0xCC, 0x10, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x85, 0xD4, 0x03, 0x84, 0x03, 0xE8, 0x00, 0x00,
0x85, 0xE0, 0x10, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x88, 0x18, 0x0B, 0x00, 0x01, 0x0B, 0x00,
0x00, 0x88, 0x2C, 0x0B, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x88, 0xF8, 0x04, 0x1A, 0x0B, 0xB8,
0x00, 0x00, 0x89, 0x3C, 0x04, 0x1A, 0x0B, 0xB8, 0x00, 0x00, 0x89, 0x80, 0x04, 0x1A, 0x0B,
0xB8, 0x00, 0x00, 0x89, 0xE0, 0x04, 0xFE, 0xF7, 0x04, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x36, 0xCC, 0x42, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x37, 0xC4, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x34, 0x68, 0x3F, 0x66, 0x66, 0x66, 0x00, 0x00, 0x39, 0xD8,
0x44, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x44, 0xB4, 0x99, 0x00, 0x11, 0x00, 0x00, 0x3A,
0x48, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3A, 0x58, 0xB4, 0x99, 0x00, 0x11, 0x00, 0x00,
0x3A, 0x5C, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3A, 0x6C, 0xB4, 0x99, 0x00, 0x11, 0x00,
0x00, 0x3A, 0x70, 0x1B, 0x8C, 0x00, 0x8F, 0x00, 0x00, 0x3B, 0x30, 0x44, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x45, 0xC8, 0x2C, 0x01, 0x50, 0x10, 0x00, 0x00, 0x45,
0xD4, 0x2D, 0x19, 0x80, 0x13, 0x00, 0x00, 0x45, 0xDC, 0x2C, 0x80, 0xB0, 0x10, 0x00, 0x00,
0x45, 0xE8, 0x2D, 0x19, 0x80, 0x13, 0x00, 0x00, 0x49, 0xC4, 0x2C, 0x00, 0x68, 0x0A, 0x00,
0x00, 0x49, 0xD0, 0x28, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x49, 0xD8, 0x2C, 0x80, 0x78, 0x0A,
0x00, 0x00, 0x49, 0xE4, 0x28, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x49, 0xF0, 0x2C, 0x00, 0x68,
0x08, 0x00, 0x00, 0x49, 0xFC, 0x23, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x4A, 0x04, 0x2C, 0x80,
0x78, 0x08, 0x00, 0x00, 0x4A, 0x10, 0x23, 0x1B, 0x80, 0x13, 0x00, 0x00, 0x5C, 0x98, 0x1E,
0x0C, 0x80, 0x80, 0x00, 0x00, 0x5C, 0xF4, 0xB4, 0x80, 0x0C, 0x90, 0x00, 0x00, 0x5D, 0x08,
0xB4, 0x80, 0x0C, 0x90, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3A, 0x1C, 0xB4, 0x94, 0x00,
0x13, 0x00, 0x00, 0x3A, 0x64, 0x2C, 0x00, 0x00, 0x15, 0x00, 0x00, 0x3A, 0x70, 0xB4, 0x92,
0x80, 0x13, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x64, 0x7C, 0xB4, 0x9A, 0x40, 0x17, 0x00, 0x00, 0x64, 0x80,
0x64, 0x00, 0x10, 0x97, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x33,
0xE4, 0x42, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x45, 0x28, 0x2C, 0x01, 0x30, 0x11, 0x00, 0x00,
0x45, 0x34, 0xB4, 0x98, 0x80, 0x13, 0x00, 0x00, 0x45, 0x3C, 0x2C, 0x81, 0x30, 0x11, 0x00,
0x00, 0x45, 0x48, 0xB4, 0x98, 0x80, 0x13, 0x00, 0x00, 0x45, 0x50, 0x2D, 0x00, 0x20, 0x11,
0x00, 0x00, 0x45, 0x5C, 0xB4, 0x98, 0x80, 0x13, 0x00, 0x00, 0x45, 0xF8, 0x2C, 0x01, 0x30,
0x0F, 0x00, 0x00, 0x46, 0x08, 0x0F, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x46, 0x0C, 0x2C, 0x81,
0x28, 0x0F, 0x00, 0x00, 0x46, 0x1C, 0x0F, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x4A, 0xEC, 0x2C,
0x00, 0x70, 0x03, 0x00, 0x00, 0x4B, 0x00, 0x2C, 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x48, 0x5C, 0x2C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x37, 0xB0, 0x3F, 0x59, 0x99, 0x9A, 0x00, 0x00,
0x37, 0xCC, 0x42, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x55, 0x20, 0x87, 0x11, 0x80, 0x13, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3B, 0x8C, 0x44, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x3D, 0x0C, 0x44, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x50, 0xE4, 0xB4, 0x99, 0x00, 0x13, 0x00, 0x00, 0x50, 0xF8, 0xB4, 0x99,
0x00, 0x13, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x4E, 0xB0, 0x02, 0xBC, 0xFF, 0x38, 0x00, 0x00, 0x4E, 0xBC, 0x14, 0x00, 0x01, 0x23,
0x00, 0x00, 0x4E, 0xC4, 0x03, 0x84, 0x01, 0xF4, 0x00, 0x00, 0x4E, 0xD0, 0x14, 0x00, 0x01,
0x23, 0x00, 0x00, 0x4E, 0xD8, 0x04, 0x4C, 0x04, 0xB0, 0x00, 0x00, 0x4E, 0xE4, 0x14, 0x00,
0x01, 0x23, 0x00, 0x00, 0x50, 0x5C, 0x2C, 0x00, 0x68, 0x15, 0x00, 0x00, 0x50, 0x6C, 0x14,
0x08, 0x01, 0x23, 0x00, 0x00, 0x50, 0x70, 0x2C, 0x80, 0x60, 0x15, 0x00, 0x00, 0x50, 0x80,
0x14, 0x08, 0x01, 0x23, 0x00, 0x00, 0x50, 0x84, 0x2D, 0x00, 0x20, 0x15, 0x00, 0x00, 0x50,
0x94, 0x14, 0x08, 0x01, 0x23, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xBA, 0x81,
0x00, 0x08, 0x80, 0x01, 0x00, 0xB4, 0x38, 0x21, 0x00, 0xB0, 0x7C, 0x08, 0x03, 0xA6, 0x3C,
0x60, 0x80, 0x3C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x2F, 0x9A, 0x3C,
0x00, 0x00, 0x00, 0x08, // #Common/PAL/Handlers/PAL Stock Icons.asm
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x30, 0x48, 0x00, 0x00, 0x21, 0x7C, 0x88,
0x02, 0xA6, 0x80, 0x64, 0x00, 0x00, 0x90, 0x7D, 0x00, 0x2C, 0x90, 0x7D, 0x00, 0x30, 0x80, 0x64, 0x00, 0x04,
0x90, 0x7D, 0x00, 0x3C, 0x48, 0x00, 0x00, 0x10, 0x4E, 0x80, 0x00, 0x21, 0x3F, 0x59, 0x99, 0x9A, 0xC1, 0xA8,
0x00, 0x00, 0x80, 0x1D, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x10, 0xFC, 0x44, 0x00, 0x00, 0x00,
0x88, 0x62, 0xF2, 0x34, 0x2C, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x30, 0x48, 0x00, 0x00,
0x21, 0x7C, 0x88, 0x02, 0xA6, 0x80, 0x64, 0x00, 0x00, 0x90, 0x7D, 0x00, 0x2C, 0x90, 0x7D,
0x00, 0x30, 0x80, 0x64, 0x00, 0x04, 0x90, 0x7D, 0x00, 0x3C, 0x48, 0x00, 0x00, 0x10, 0x4E,
0x80, 0x00, 0x21, 0x3F, 0x59, 0x99, 0x9A, 0xC1, 0xA8, 0x00, 0x00, 0x80, 0x1D, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0xC2, 0x10, 0xFC, 0x44, 0x00, 0x00, 0x00,
0x04, // #Common/PAL/Handlers/DK
// Up B/Aerial Up B.asm
0x88, 0x82, 0xF2, 0x34, 0x2C, 0x04, 0x00, 0x00, 0x41, 0x82, 0x00, 0x10, 0x3C, 0x00, 0x80, 0x11, 0x60, 0x00,
0x00, 0x74, 0x48, 0x00, 0x00, 0x08, 0x38, 0x03, 0xD7, 0x74, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x10, 0xFB, 0x64,
0x00, 0x00, 0x00, 0x04, // #Common/PAL/Handlers/DK Up B/Grounded
// Up B.asm
0x88, 0x82, 0xF2, 0x34, 0x2C, 0x04, 0x00, 0x00, 0x41, 0x82, 0x00, 0x10, 0x3C, 0x00, 0x80, 0x11, 0x60, 0x00,
0x00, 0x74, 0x48, 0x00, 0x00, 0x08, 0x38, 0x03, 0xD7, 0x74, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 // Termination sequence
0x88, 0x82, 0xF2, 0x34, 0x2C, 0x04, 0x00, 0x00, 0x41, 0x82, 0x00, 0x10, 0x3C, 0x00, 0x80,
0x11, 0x60, 0x00, 0x00, 0x74, 0x48, 0x00, 0x00, 0x08, 0x38, 0x03, 0xD7, 0x74, 0x00, 0x00,
0x00, 0x00, 0xC2, 0x10, 0xFB, 0x64, 0x00, 0x00, 0x00, 0x04, // #Common/PAL/Handlers/DK Up
// B/Grounded Up B.asm
0x88, 0x82, 0xF2, 0x34, 0x2C, 0x04, 0x00, 0x00, 0x41, 0x82, 0x00, 0x10, 0x3C, 0x00, 0x80,
0x11, 0x60, 0x00, 0x00, 0x74, 0x48, 0x00, 0x00, 0x08, 0x38, 0x03, 0xD7, 0x74, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Termination sequence
};
static std::unordered_map<u32, bool> staticBlacklist = {
@ -925,7 +976,8 @@ void CEXISlippi::prepareGeckoList()
{0x8016e74c, true}, // Recording/SendGameInfo.asm
{0x8006c5d8, true}, // Recording/SendGamePostFrame.asm
{0x8006b0dc, true}, // Recording/SendGamePreFrame.asm
{0x803219ec, true}, // 3.4.0: Recording/FlushFrameBuffer.asm (Have to keep old ones for backward compatibility)
{0x803219ec, true}, // 3.4.0: Recording/FlushFrameBuffer.asm (Have to keep old ones for
// backward compatibility)
{0x8006da34, true}, // 3.4.0: Recording/SendGamePostFrame.asm
{0x8016d884, true}, // 3.7.0: Recording/SendGameEnd.asm
@ -963,20 +1015,22 @@ void CEXISlippi::prepareGeckoList()
{0x801a4570, true}, // External/LagReduction/ForceHD/480pDeflickerOff.asm
{0x802fccd8, true}, // External/Hide Nametag When Invisible/Hide Nametag When Invisible.asm
{0x804ddb30,
true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble Positions/Adjust Corner Value 1.asm
{0x804ddb34,
true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble Positions/Adjust Corner Value 2.asm
{0x804ddb2c, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble Positions/Extend Negative
// Vertical Bound.asm
{0x804ddb28, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble Positions/Extend Positive
// Vertical Bound.asm
{0x804ddb4c, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble Positions/Widen Bubble Region.asm
{0x804ddb30, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble
// Positions/Adjust Corner Value 1.asm
{0x804ddb34, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble
// Positions/Adjust Corner Value 2.asm
{0x804ddb2c, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble
// Positions/Extend Negative Vertical Bound.asm
{0x804ddb28, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble
// Positions/Extend Positive Vertical Bound.asm
{0x804ddb4c, true}, // External/Widescreen/Adjust Offscreen Scissor/Fix Bubble
// Positions/Widen Bubble Region.asm
{0x804ddb58, true}, // External/Widescreen/Adjust Offscreen Scissor/Adjust Bubble Zoom.asm
{0x80086b24, true}, // External/Widescreen/Adjust Offscreen Scissor/Draw High Poly Models.asm
{0x80030C7C, true}, // External/Widescreen/Adjust Offscreen Scissor/Left Camera Bound.asm
{0x80030C88, true}, // External/Widescreen/Adjust Offscreen Scissor/Right Camera Bound.asm
{0x802fcfc4, true}, // External/Widescreen/Nametag Fixes/Adjust Nametag Background X Scale.asm
{0x802fcfc4,
true}, // External/Widescreen/Nametag Fixes/Adjust Nametag Background X Scale.asm
{0x804ddb84, true}, // External/Widescreen/Nametag Fixes/Adjust Nametag Text X Scale.asm
{0x803BB05C, true}, // External/Widescreen/Fix Screen Flash.asm
{0x8036A4A8, true}, // External/Widescreen/Overwrite CObj Values.asm
@ -1040,7 +1094,8 @@ void CEXISlippi::prepareGeckoList()
while (idx < source.size())
{
u8 codeType = source[idx] & 0xFE;
u32 address = source[idx] << 24 | source[idx + 1] << 16 | source[idx + 2] << 8 | source[idx + 3];
u32 address =
source[idx] << 24 | source[idx + 1] << 16 | source[idx + 2] << 8 | source[idx + 3];
address = (address & 0x01FFFFFF) | 0x80000000;
u32 codeOffset = 8; // Default code offset. Most codes are this length
@ -1049,7 +1104,8 @@ void CEXISlippi::prepareGeckoList()
case 0xC0:
case 0xC2:
{
u32 lineCount = source[idx + 4] << 24 | source[idx + 5] << 16 | source[idx + 6] << 8 | source[idx + 7];
u32 lineCount =
source[idx + 4] << 24 | source[idx + 5] << 16 | source[idx + 6] << 8 | source[idx + 7];
codeOffset = 8 + (lineCount * 8);
break;
}
@ -1058,8 +1114,10 @@ void CEXISlippi::prepareGeckoList()
break;
case 0x06:
{
u32 byteLen = source[idx + 4] << 24 | source[idx + 5] << 16 | source[idx + 6] << 8 | source[idx + 7];
codeOffset = 8 + ((byteLen + 7) & 0xFFFFFFF8); // Round up to next 8 bytes and add the first 8 bytes
u32 byteLen =
source[idx + 4] << 24 | source[idx + 5] << 16 | source[idx + 6] << 8 | source[idx + 7];
codeOffset =
8 + ((byteLen + 7) & 0xFFFFFFF8); // Round up to next 8 bytes and add the first 8 bytes
break;
}
}
@ -1070,8 +1128,8 @@ void CEXISlippi::prepareGeckoList()
if (blacklist.count(address))
continue;
INFO_LOG(SLIPPI, "Codetype [%x] Inserting section: %d - %d (%x, %d)", codeType, idx - codeOffset, idx, address,
codeOffset);
INFO_LOG(SLIPPI, "Codetype [%x] Inserting section: %d - %d (%x, %d)", codeType,
idx - codeOffset, idx, address, codeOffset);
// If not blacklisted, add code to return vector
geckoList.insert(geckoList.end(), source.begin() + (idx - codeOffset), source.begin() + idx);
@ -1100,12 +1158,12 @@ void CEXISlippi::prepareCharacterFrameData(Slippi::FrameData* frame, u8 port, u8
// Get data for this player
Slippi::PlayerFrameData data = source[port];
// log << frameIndex << "\t" << port << "\t" << data.locationX << "\t" << data.locationY << "\t" <<
// data.animation
// log << frameIndex << "\t" << port << "\t" << data.locationX << "\t" << data.locationY << "\t"
// << data.animation
// << "\n";
// WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] [Player %d] Positions: %f | %f", frameIndex, port, data.locationX,
// data.locationY);
// WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] [Player %d] Positions: %f | %f", frameIndex, port,
// data.locationX, data.locationY);
// Add all of the inputs in order
appendWordToBuffer(&m_read_queue, data.randomSeed);
@ -1249,7 +1307,8 @@ void CEXISlippi::prepareFrameData(u8* payload)
if (requestResultCode == FRAME_RESP_TERMINATE)
{
ERROR_LOG(EXPANSIONINTERFACE, "Game should terminate on frame %d [%X]", frameIndex, frameIndex);
ERROR_LOG(EXPANSIONINTERFACE, "Game should terminate on frame %d [%X]", frameIndex,
frameIndex);
}
return;
@ -1429,8 +1488,10 @@ void CEXISlippi::handleOnlineInputs(u8* payload)
bool CEXISlippi::shouldSkipOnlineFrame(s32 frame)
{
auto status = slippi_netplay->GetSlippiConnectStatus();
bool connectionFailed = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_FAILED;
bool connectionDisconnected = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED;
bool connectionFailed =
status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_FAILED;
bool connectionDisconnected =
status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED;
if (connectionFailed || connectionDisconnected)
{
// If connection failed just continue the game
@ -1454,7 +1515,8 @@ bool CEXISlippi::shouldSkipOnlineFrame(s32 frame)
isConnectionStalled = true;
}
WARN_LOG(SLIPPI_ONLINE, "Halting for one frame due to rollback limit (frame: %d | latest: %d)...", frame,
WARN_LOG(SLIPPI_ONLINE,
"Halting for one frame due to rollback limit (frame: %d | latest: %d)...", frame,
latestRemoteFrame);
return true;
}
@ -1463,9 +1525,9 @@ bool CEXISlippi::shouldSkipOnlineFrame(s32 frame)
// Return true if we are over 60% of a frame ahead of our opponent. Currently limiting how
// often this happens because I'm worried about jittery data causing a lot of unneccesary delays.
// Only skip once for a given frame because our time detection method doesn't take into consideration
// waiting for a frame. Also it's less jarring and it happens often enough that it will smoothly
// get to the right place
// Only skip once for a given frame because our time detection method doesn't take into
// consideration waiting for a frame. Also it's less jarring and it happens often enough that it
// will smoothly get to the right place
auto isTimeSyncFrame = frame % SLIPPI_ONLINE_LOCKSTEP_INTERVAL; // Only time sync every 30 frames
if (isTimeSyncFrame == 0 && !isCurrentlySkipping)
{
@ -1478,10 +1540,11 @@ bool CEXISlippi::shouldSkipOnlineFrame(s32 frame)
int maxSkipFrames = frame <= 120 ? 5 : 1; // On early frames, support skipping more frames
framesToSkip = ((offsetUs - 10000) / 16683) + 1;
framesToSkip = framesToSkip > maxSkipFrames ? maxSkipFrames : framesToSkip; // Only skip 5 frames max
framesToSkip =
framesToSkip > maxSkipFrames ? maxSkipFrames : framesToSkip; // Only skip 5 frames max
WARN_LOG(SLIPPI_ONLINE, "Halting on frame %d due to time sync. Offset: %d us. Frames: %d...", frame,
offsetUs, framesToSkip);
WARN_LOG(SLIPPI_ONLINE, "Halting on frame %d due to time sync. Offset: %d us. Frames: %d...",
frame, offsetUs, framesToSkip);
}
}
@ -1519,7 +1582,8 @@ void CEXISlippi::prepareOpponentInputs(u8* payload)
u8 frameResult = 1; // Indicates to continue frame
auto state = slippi_netplay->GetSlippiConnectStatus();
if (state != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED || isConnectionStalled)
if (state != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED ||
isConnectionStalled)
{
frameResult = 3; // Indicates we have disconnected
}
@ -1548,8 +1612,9 @@ void CEXISlippi::prepareOpponentInputs(u8* payload)
m_read_queue.insert(m_read_queue.end(), tx.begin(), tx.end());
// ERROR_LOG(SLIPPI_ONLINE, "EXI: [%d] %X %X %X %X %X %X %X %X", latestFrame, m_read_queue[5], m_read_queue[6],
// m_read_queue[7], m_read_queue[8], m_read_queue[9], m_read_queue[10], m_read_queue[11], m_read_queue[12]);
// ERROR_LOG(SLIPPI_ONLINE, "EXI: [%d] %X %X %X %X %X %X %X %X", latestFrame, m_read_queue[5],
// m_read_queue[6], m_read_queue[7], m_read_queue[8], m_read_queue[9], m_read_queue[10],
// m_read_queue[11], m_read_queue[12]);
}
void CEXISlippi::handleCaptureSavestate(u8* payload)
@ -1609,7 +1674,8 @@ void CEXISlippi::handleLoadSavestate(u8* payload)
int idx = 0;
while (Common::swap32(preserveArr[idx]) != 0)
{
SlippiSavestate::PreserveBlock p = { Common::swap32(preserveArr[idx]), Common::swap32(preserveArr[idx + 1]) };
SlippiSavestate::PreserveBlock p = {Common::swap32(preserveArr[idx]),
Common::swap32(preserveArr[idx + 1])};
blocks.push_back(p);
idx += 2;
}
@ -1626,7 +1692,8 @@ void CEXISlippi::handleLoadSavestate(u8* payload)
activeSavestates.clear();
u32 timeDiff = (u32)(Common::Timer::GetTimeUs() - startTime);
INFO_LOG(SLIPPI_ONLINE, "SLIPPI ONLINE: Loaded savestate for frame %d in: %f ms", frame, ((double)timeDiff) / 1000);
INFO_LOG(SLIPPI_ONLINE, "SLIPPI ONLINE: Loaded savestate for frame %d in: %f ms", frame,
((double)timeDiff) / 1000);
}
void CEXISlippi::startFindMatch(u8* payload)
@ -1645,9 +1712,9 @@ void CEXISlippi::startFindMatch(u8* payload)
// Store this search so we know what was queued for
lastSearch = search;
// While we do have another condition that checks characters after being connected, it's nice to give
// someone an early error before they even queue so that they wont enter the queue and make someone
// else get force removed from queue and have to requeue
// While we do have another condition that checks characters after being connected, it's nice to
// give someone an early error before they even queue so that they wont enter the queue and make
// someone else get force removed from queue and have to requeue
auto directMode = SlippiMatchmaking::OnlinePlayMode::DIRECT;
if (search.mode != directMode && localSelections.characterId >= 26)
{
@ -1672,34 +1739,38 @@ void CEXISlippi::startFindMatch(u8* payload)
void CEXISlippi::prepareOnlineMatchState()
{
// This match block is a VS match with P1 Red Falco vs P2 Red Bowser on Battlefield. The proper values will
// be overwritten
// This match block is a VS match with P1 Red Falco vs P2 Red Bowser on Battlefield. The proper
// values will be overwritten
static std::vector<u8> onlineMatchBlock = {
0x32, 0x01, 0x86, 0x4C, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6E, 0x00, 0x1F, 0x00, 0x00,
0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x1A, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x1A, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
0x32, 0x01, 0x86, 0x4C, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x6E, 0x00,
0x1F, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F,
0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09,
0x00, 0x78, 0x00, 0xC0, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x05, 0x00, 0x04,
0x01, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0xC0, 0x00, 0x04, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F,
0x80, 0x00, 0x00, 0x1A, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00,
0x40, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00,
0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x1A, 0x03, 0x04, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0x40, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09, 0x00, 0x78, 0x00, 0x40, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80,
0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x21, 0x03, 0x04, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x09,
0x00, 0x78, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00,
};
m_read_queue.clear();
auto errorState = SlippiMatchmaking::ProcessState::ERROR_ENCOUNTERED;
SlippiMatchmaking::ProcessState mmState = !forcedError.empty() ? errorState : matchmaking->GetMatchmakeState();
SlippiMatchmaking::ProcessState mmState =
!forcedError.empty() ? errorState : matchmaking->GetMatchmakeState();
#ifdef LOCAL_TESTING
if (localSelections.isCharacterSelected || isLocalConnected)
@ -1735,7 +1806,8 @@ void CEXISlippi::prepareOnlineMatchState()
bool isConnected = true;
#else
auto status = slippi_netplay->GetSlippiConnectStatus();
bool isConnected = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED;
bool isConnected =
status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED;
#endif
if (isConnected)
@ -1815,8 +1887,8 @@ void CEXISlippi::prepareOnlineMatchState()
onlineMatchBlock[0x63 + remotePlayerIndex * 0x24] = rps.characterColor;
// Make one character lighter if same character, same color
bool isSheikVsZelda =
lps.characterId == 0x12 && rps.characterId == 0x13 || lps.characterId == 0x13 && rps.characterId == 0x12;
bool isSheikVsZelda = lps.characterId == 0x12 && rps.characterId == 0x13 ||
lps.characterId == 0x13 && rps.characterId == 0x12;
bool charMatch = lps.characterId == rps.characterId || isSheikVsZelda;
bool colMatch = lps.characterColor == rps.characterColor;
@ -1843,7 +1915,8 @@ void CEXISlippi::prepareOnlineMatchState()
// Set rng offset
rngOffset = isDecider ? lps.rngOffset : rps.rngOffset;
WARN_LOG(SLIPPI_ONLINE, "Rng Offset: 0x%x", rngOffset);
WARN_LOG(SLIPPI_ONLINE, "P1 Char: 0x%X, P2 Char: 0x%X", onlineMatchBlock[0x60], onlineMatchBlock[0x84]);
WARN_LOG(SLIPPI_ONLINE, "P1 Char: 0x%X, P2 Char: 0x%X", onlineMatchBlock[0x60],
onlineMatchBlock[0x84]);
// Set player names
p1Name = isDecider ? lps.playerName : rps.playerName;
@ -1989,8 +2062,8 @@ void CEXISlippi::logMessageFromGame(u8* payload)
}
else
{
GENERIC_LOG(Common::Log::SLIPPI, (Common::Log::LOG_LEVELS)payload[1], "%s: %llu", (char*)& payload[2],
Common::Timer::GetTimeUs());
GENERIC_LOG(Common::Log::SLIPPI, (Common::Log::LOG_LEVELS)payload[1], "%s: %llu",
(char*)&payload[2], Common::Timer::GetTimeUs());
}
}
@ -2015,8 +2088,8 @@ void CEXISlippi::handleLogOutRequest()
void CEXISlippi::handleUpdateAppRequest()
{
#ifdef __APPLE__
CriticalAlertT(
"Automatic updates are not available for macOS, please get the latest update from slippi.gg/netplay.");
CriticalAlertT("Automatic updates are not available for macOS, please get the latest update from "
"slippi.gg/netplay.");
#else
Host_LowerWindow();
user->UpdateApp();
@ -2056,7 +2129,8 @@ void CEXISlippi::prepareOnlineStatus()
m_read_queue.insert(m_read_queue.end(), codeBuf, codeBuf + CONNECT_CODE_LENGTH + 2);
}
void doConnectionCleanup(std::unique_ptr<SlippiMatchmaking> mm, std::unique_ptr<SlippiNetplayClient> nc)
void doConnectionCleanup(std::unique_ptr<SlippiMatchmaking> mm,
std::unique_ptr<SlippiNetplayClient> nc)
{
if (mm)
mm.reset();
@ -2119,8 +2193,9 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
bufLoc += receiveCommandsLen + 1;
}
INFO_LOG(EXPANSIONINTERFACE, "EXI SLIPPI DMAWrite: addr: 0x%08x size: %d, bufLoc:[%02x %02x %02x %02x %02x]",
_uAddr, _uSize, memPtr[bufLoc], memPtr[bufLoc + 1], memPtr[bufLoc + 2], memPtr[bufLoc + 3],
INFO_LOG(EXPANSIONINTERFACE,
"EXI SLIPPI DMAWrite: addr: 0x%08x size: %d, bufLoc:[%02x %02x %02x %02x %02x]", _uAddr,
_uSize, memPtr[bufLoc], memPtr[bufLoc + 1], memPtr[bufLoc + 2], memPtr[bufLoc + 3],
memPtr[bufLoc + 4]);
while (bufLoc < _uSize)
@ -2218,8 +2293,9 @@ void CEXISlippi::DMARead(u32 addr, u32 size)
m_read_queue.resize(size, 0); // Resize response array to make sure it's all full/allocated
auto queueAddr = &m_read_queue[0];
INFO_LOG(EXPANSIONINTERFACE, "EXI SLIPPI DMARead: addr: 0x%08x size: %d, startResp: [%02x %02x %02x %02x %02x]",
addr, size, queueAddr[0], queueAddr[1], queueAddr[2], queueAddr[3], queueAddr[4]);
INFO_LOG(EXPANSIONINTERFACE,
"EXI SLIPPI DMARead: addr: 0x%08x size: %d, startResp: [%02x %02x %02x %02x %02x]", addr,
size, queueAddr[0], queueAddr[1], queueAddr[2], queueAddr[3], queueAddr[4]);
// Copy buffer data to memory
Memory::CopyToEmu(addr, queueAddr, size);
@ -2230,5 +2306,7 @@ bool CEXISlippi::IsPresent() const
return true;
}
void CEXISlippi::TransferByte(u8& byte) {}
void CEXISlippi::TransferByte(u8& byte)
{
}
} // namespace ExpansionInterface

View file

@ -7,9 +7,8 @@
#include <SlippiGame.h>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/File.h"
#include "EXI_Device.h"
#include "Common/FileUtil.h"
#include "Core/Slippi/SlippiGameFileLoader.h"
#include "Core/Slippi/SlippiMatchmaking.h"
#include "Core/Slippi/SlippiNetplay.h"
@ -17,6 +16,7 @@
#include "Core/Slippi/SlippiReplayComm.h"
#include "Core/Slippi/SlippiSavestate.h"
#include "Core/Slippi/SlippiUser.h"
#include "EXI_Device.h"
#define ROLLBACK_MAX_FRAMES 7
#define MAX_NAME_LENGTH 15
@ -222,4 +222,4 @@ namespace ExpansionInterface
std::map<s32, std::unique_ptr<SlippiSavestate>> activeSavestates;
std::deque<std::unique_ptr<SlippiSavestate>> availableSavestates;
};
}
} // namespace ExpansionInterface

View file

@ -1,12 +1,12 @@
#include "SlippiGameFileLoader.h"
#include "Common/Logging/Log.h"
#include "Common/FileUtil.h"
#include "Common/File.h"
#include "Core/HW/DVD/DVDThread.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Core/Boot/Boot.h"
#include "Core/Core.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/DVD/DVDThread.h"
std::string getFilePath(std::string fileName)
{
@ -49,8 +49,10 @@ u32 SlippiGameFileLoader::LoadFile(std::string fileName, std::string& data)
std::string fileContents;
File::ReadFileToString(gameFilePath, fileContents);
// If the file was a diff file and the game is running, load the main file from ISO and apply patch
if (gameFilePath.substr(gameFilePath.length() - 5) == ".diff" && Core::GetState() == Core::State::Running)
// If the file was a diff file and the game is running, load the main file from ISO and apply
// patch
if (gameFilePath.substr(gameFilePath.length() - 5) == ".diff" &&
Core::GetState() == Core::State::Running)
{
std::vector<u8> buf;
INFO_LOG(SLIPPI, "Will process diff");

View file

@ -1,10 +1,10 @@
#pragma once
#include "Common/CommonTypes.h"
#include <open-vcdiff/src/google/vcdecoder.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "Common/CommonTypes.h"
class SlippiGameFileLoader
{

View file

@ -1,11 +1,11 @@
#include "SlippiMatchmaking.h"
#include <string>
#include <vector>
#include "Common/Common.h"
#include "Common/Version.h"
#include "Common/ENetUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include <string>
#include <vector>
#include "Common/Version.h"
class MmMessageType
{
@ -28,7 +28,8 @@ SlippiMatchmaking::SlippiMatchmaking(SlippiUser* user)
m_client = nullptr;
m_server = nullptr;
MM_HOST = Common::scm_slippi_semver_str.find("dev") == std::string::npos ? MM_HOST_PROD : MM_HOST_DEV;
MM_HOST =
Common::scm_slippi_semver_str.find("dev") == std::string::npos ? MM_HOST_PROD : MM_HOST_DEV;
generator = std::default_random_engine(Common::Timer::GetTimeMs());
}
@ -111,7 +112,8 @@ int SlippiMatchmaking::receiveMessage(json& msg, int timeoutMs)
case ENET_EVENT_TYPE_RECEIVE:
{
std::vector<u8> buf;
buf.insert(buf.end(), netEvent.packet->data, netEvent.packet->data + netEvent.packet->dataLength);
buf.insert(buf.end(), netEvent.packet->data,
netEvent.packet->data + netEvent.packet->dataLength);
std::string str(buf.begin(), buf.end());
INFO_LOG(SLIPPI_ONLINE, "[Matchmaking] Received: %s", str.c_str());
@ -296,7 +298,8 @@ void SlippiMatchmaking::startMatchmaking()
int rcvRes = receiveMessage(response, 5000);
if (rcvRes != 0)
{
ERROR_LOG(SLIPPI_ONLINE, "[Matchmaking] Did not receive response from server for create ticket");
ERROR_LOG(SLIPPI_ONLINE,
"[Matchmaking] Did not receive response from server for create ticket");
m_state = ProcessState::ERROR_ENCOUNTERED;
m_errorMsg = "Failed to join mm queue";
return;
@ -364,7 +367,8 @@ void SlippiMatchmaking::handleMatchmaking()
if (latestVersion != "")
{
// Update file to get new version number when the mm server tells us our version is outdated
m_user->OverwriteLatestVersion(latestVersion); // Force latest version for people whose file updates dont work
m_user->OverwriteLatestVersion(
latestVersion); // Force latest version for people whose file updates dont work
}
ERROR_LOG(SLIPPI_ONLINE, "[Matchmaking] Received error from server for get ticket");
@ -382,7 +386,8 @@ void SlippiMatchmaking::handleMatchmaking()
terminateMmConnection();
m_state = ProcessState::OPPONENT_CONNECTING;
ERROR_LOG(SLIPPI_ONLINE, "[Matchmaking] Opponent found. isDecider: %s", m_isHost ? "true" : "false");
ERROR_LOG(SLIPPI_ONLINE, "[Matchmaking] Opponent found. isDecider: %s",
m_isHost ? "true" : "false");
}
void SlippiMatchmaking::handleConnecting()
@ -390,7 +395,8 @@ void SlippiMatchmaking::handleConnecting()
std::vector<std::string> ipParts = SplitString(m_oppIp, ':');
// Is host is now used to specify who the decider is
auto client = std::make_unique<SlippiNetplayClient>(ipParts[0], std::stoi(ipParts[1]), m_hostPort, m_isHost);
auto client = std::make_unique<SlippiNetplayClient>(ipParts[0], std::stoi(ipParts[1]), m_hostPort,
m_isHost);
while (!m_netplayClient)
{
@ -408,7 +414,8 @@ void SlippiMatchmaking::handleConnecting()
}
else if (status != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED)
{
ERROR_LOG(SLIPPI_ONLINE, "[Matchmaking] Connection attempt failed, looking for someone else.");
ERROR_LOG(SLIPPI_ONLINE,
"[Matchmaking] Connection attempt failed, looking for someone else.");
// Return to the start to get a new ticket to find someone else we can hopefully connect with
m_netplayClient = nullptr;

View file

@ -6,9 +6,9 @@
#include "Core/Slippi/SlippiUser.h"
#include <enet/enet.h>
#include <random>
#include <unordered_map>
#include <vector>
#include <random>
#include <nlohmann/json.hpp>
using json = nlohmann::json;

View file

@ -11,10 +11,10 @@
#include "Common/MD5.h"
#include "Common/MsgHandler.h"
#include "Common/Timer.h"
#include "Core/ConfigManager.h"
#include "Core/NetPlayProto.h"
#include "Core/Core.h"
#include "Core/Config/NetplaySettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/NetPlayProto.h"
//#include "Core/HW/EXI_DeviceIPL.h"
//#include "Core/HW/SI.h"
//#include "Core/HW/SI_DeviceGCController.h"
@ -22,16 +22,16 @@
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
//#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h"
#include "Core/Movie.h"
#include "InputCommon/GCAdapter.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
#include <SlippiGame.h>
#include <algorithm>
#include <fstream>
#include <mbedtls/md5.h>
#include <memory>
#include <thread>
#include "Core/Movie.h"
#include "InputCommon/GCAdapter.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
static std::mutex pad_mutex;
static std::mutex ack_mutex;
@ -62,11 +62,10 @@ SlippiNetplayClient::~SlippiNetplayClient()
}
// called from ---SLIPPI EXI--- thread
SlippiNetplayClient::SlippiNetplayClient(const std::string& address, const u16 remotePort, const u16 localPort,
bool isDecider)
SlippiNetplayClient::SlippiNetplayClient(const std::string& address, const u16 remotePort,
const u16 localPort, bool isDecider)
#ifdef _WIN32
: m_qos_handle(nullptr)
, m_qos_flow_id(0)
: m_qos_handle(nullptr), m_qos_flow_id(0)
#endif
{
WARN_LOG(SLIPPI_ONLINE, "Initializing Slippi Netplay for port: %d, with host: %s", localPort,
@ -78,9 +77,10 @@ SlippiNetplayClient::SlippiNetplayClient(const std::string& address, const u16 r
ENetAddress* localAddr = nullptr;
ENetAddress localAddrDef;
// It is important to be able to set the local port to listen on even in a client connection because
// not doing so will break hole punching, the host is expecting traffic to come from a specific ip/port
// and if the port does not match what it is expecting, it will not get through the NAT on some routers
// It is important to be able to set the local port to listen on even in a client connection
// because not doing so will break hole punching, the host is expecting traffic to come from a
// specific ip/port and if the port does not match what it is expecting, it will not get through
// the NAT on some routers
if (localPort > 0)
{
INFO_LOG(SLIPPI_ONLINE, "Setting up local address");
@ -91,7 +91,8 @@ SlippiNetplayClient::SlippiNetplayClient(const std::string& address, const u16 r
localAddr = &localAddrDef;
}
// TODO: Figure out how to use a local port when not hosting without accepting incoming connections
// TODO: Figure out how to use a local port when not hosting without accepting incoming
// connections
m_client = enet_host_create(localAddr, 2, 3, 0, 0);
if (m_client == nullptr)
@ -126,7 +127,8 @@ SlippiNetplayClient::SlippiNetplayClient(bool isDecider)
unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
{
NetPlay::MessageId mid = 0;
if (!(packet >> mid)) {
if (!(packet >> mid))
{
ERROR_LOG(SLIPPI_ONLINE, "Received empty netplay packet");
return 0;
}
@ -136,7 +138,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
case NetPlay::NP_MSG_SLIPPI_PAD:
{
int32_t frame;
if (!(packet >> frame)) {
if (!(packet >> frame))
{
ERROR_LOG(SLIPPI_ONLINE, "Netplay packet too small to read frame count");
break;
}
@ -151,8 +154,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
auto timing = lastFrameTiming;
if (!hasGameStarted)
{
// Handle case where opponent starts sending inputs before our game has reached frame 1. This will
// continuously say frame 0 is now to prevent opp from getting too far ahead
// Handle case where opponent starts sending inputs before our game has reached frame 1. This
// will continuously say frame 0 is now to prevent opp from getting too far ahead
timing.frame = 0;
timing.timeUs = curTime;
}
@ -161,8 +164,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
s64 frameDiffOffsetUs = 16683 * (timing.frame - frame);
s64 timeOffsetUs = opponentSendTimeUs - timing.timeUs + frameDiffOffsetUs;
INFO_LOG(SLIPPI_ONLINE, "[Offset] Opp Frame: %d, My Frame: %d. Time offset: %lld", frame, timing.frame,
timeOffsetUs);
INFO_LOG(SLIPPI_ONLINE, "[Offset] Opp Frame: %d, My Frame: %d. Time offset: %lld", frame,
timing.frame, timeOffsetUs);
// Add this offset to circular buffer for use later
if (frameOffsetData.buf.size() < SLIPPI_ONLINE_LOCKSTEP_INTERVAL)
@ -183,18 +186,20 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
int inputsToCopy = frame - headFrame;
// Check that the packet actually contains the data it claims to
if ((5 + inputsToCopy * SLIPPI_PAD_DATA_SIZE) > (int)packet.getDataSize()) {
if ((5 + inputsToCopy * SLIPPI_PAD_DATA_SIZE) > (int)packet.getDataSize())
{
ERROR_LOG(SLIPPI_ONLINE, "Netplay packet too small to read pad buffer");
break;
}
for (int i = inputsToCopy - 1; i >= 0; i--)
{
auto pad = std::make_unique<SlippiPad>(frame - i, &packetData[5 + i * SLIPPI_PAD_DATA_SIZE]);
auto pad =
std::make_unique<SlippiPad>(frame - i, &packetData[5 + i * SLIPPI_PAD_DATA_SIZE]);
INFO_LOG(SLIPPI_ONLINE, "Rcv [%d] -> %02X %02X %02X %02X %02X %02X %02X %02X", pad->frame,
pad->padBuf[0], pad->padBuf[1], pad->padBuf[2], pad->padBuf[3], pad->padBuf[4], pad->padBuf[5],
pad->padBuf[6], pad->padBuf[7]);
pad->padBuf[0], pad->padBuf[1], pad->padBuf[2], pad->padBuf[3], pad->padBuf[4],
pad->padBuf[5], pad->padBuf[6], pad->padBuf[7]);
remotePadQueue.push_front(std::move(pad));
}
@ -214,7 +219,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
// Store last frame acked
int32_t frame;
if (!(packet >> frame)) {
if (!(packet >> frame))
{
ERROR_LOG(SLIPPI_ONLINE, "Ack packet too small to read frame");
break;
}
@ -239,8 +245,9 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
pingUs = Common::Timer::GetTimeUs() - sendTime;
if (g_ActiveConfig.bShowNetPlayPing && frame % SLIPPI_PING_DISPLAY_INTERVAL == 0)
{
OSD::AddTypedMessage(OSD::MessageType::NetPlayPing, StringFromFormat("Ping: %u", pingUs / 1000),
OSD::Duration::NORMAL, OSD::Color::CYAN);
OSD::AddTypedMessage(OSD::MessageType::NetPlayPing,
StringFromFormat("Ping: %u", pingUs / 1000), OSD::Duration::NORMAL,
OSD::Color::CYAN);
}
}
break;
@ -259,7 +266,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
// This might be a good place to reset some logic? Game can't start until we receive this msg
// so this should ensure that everything is initialized before the game starts
// TODO: This could cause issues in the case of a desync? If this is ever received mid-game, bad things
// TODO: This could cause issues in the case of a desync? If this is ever received mid-game, bad
// things
// TODO: will happen. Consider improving this
hasGameStarted = false;
}
@ -267,7 +275,8 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet)
case NetPlay::NP_MSG_SLIPPI_CONN_SELECTED:
{
// Currently this is unused but the intent is to support two-way simultaneous connection attempts
// Currently this is unused but the intent is to support two-way simultaneous connection
// attempts
isConnectionSelected = true;
}
break;
@ -290,7 +299,8 @@ void SlippiNetplayClient::writeToPacket(sf::Packet& packet, SlippiPlayerSelectio
packet << s.connectCode;
}
std::unique_ptr<SlippiPlayerSelections> SlippiNetplayClient::readSelectionsFromPacket(sf::Packet& packet)
std::unique_ptr<SlippiPlayerSelections>
SlippiNetplayClient::readSelectionsFromPacket(sf::Packet& packet)
{
auto s = std::make_unique<SlippiPlayerSelections>();
@ -424,7 +434,8 @@ void SlippiNetplayClient::ThreadFunc()
// this will fail if we're not admin
// sets DSCP to the same as linux (0x2e)
QOSSetFlow(m_qos_handle, m_qos_flow_id, QOSSetOutgoingDSCPValue, sizeof(DWORD), &dscp, 0, nullptr);
QOSSetFlow(m_qos_handle, m_qos_flow_id, QOSSetOutgoingDSCPValue, sizeof(DWORD), &dscp, 0,
nullptr);
qos_success = true;
}
@ -441,7 +452,8 @@ void SlippiNetplayClient::ThreadFunc()
// https://www.tucny.com/Home/dscp-tos
// ef is better than cs7
int tos_val = 0xb8;
qos_success = setsockopt(m_server->host->socket, IPPROTO_IP, IP_TOS, &tos_val, sizeof(tos_val)) == 0;
qos_success =
setsockopt(m_server->host->socket, IPPROTO_IP, IP_TOS, &tos_val, sizeof(tos_val)) == 0;
}
#endif
@ -550,8 +562,10 @@ void SlippiNetplayClient::SendConnectionSelected()
void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
{
auto status = slippiConnectStatus;
bool connectionFailed = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_FAILED;
bool connectionDisconnected = status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED;
bool connectionFailed =
status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_FAILED;
bool connectionDisconnected =
status == SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_DISCONNECTED;
if (connectionFailed || connectionDisconnected)
{
return;
@ -559,8 +573,9 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
// if (pad && isDecider)
//{
// ERROR_LOG(SLIPPI_ONLINE, "[%d] %X %X %X %X %X %X %X %X", pad->frame, pad->padBuf[0], pad->padBuf[1],
// pad->padBuf[2], pad->padBuf[3], pad->padBuf[4], pad->padBuf[5], pad->padBuf[6], pad->padBuf[7]);
// ERROR_LOG(SLIPPI_ONLINE, "[%d] %X %X %X %X %X %X %X %X", pad->frame, pad->padBuf[0],
// pad->padBuf[1], pad->padBuf[2], pad->padBuf[3], pad->padBuf[4], pad->padBuf[5],
// pad->padBuf[6], pad->padBuf[7]);
//}
if (pad)
@ -590,9 +605,9 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
INFO_LOG(SLIPPI_ONLINE, "Sending a packet of inputs [%d]...", frame);
for (auto it = localPadQueue.begin(); it != localPadQueue.end(); ++it)
{
INFO_LOG(SLIPPI_ONLINE, "Send [%d] -> %02X %02X %02X %02X %02X %02X %02X %02X", (*it)->frame, (*it)->padBuf[0],
(*it)->padBuf[1], (*it)->padBuf[2], (*it)->padBuf[3], (*it)->padBuf[4], (*it)->padBuf[5],
(*it)->padBuf[6], (*it)->padBuf[7]);
INFO_LOG(SLIPPI_ONLINE, "Send [%d] -> %02X %02X %02X %02X %02X %02X %02X %02X", (*it)->frame,
(*it)->padBuf[0], (*it)->padBuf[1], (*it)->padBuf[2], (*it)->padBuf[3],
(*it)->padBuf[4], (*it)->padBuf[5], (*it)->padBuf[6], (*it)->padBuf[7]);
spac->append((*it)->padBuf, SLIPPI_PAD_DATA_SIZE); // only transfer 8 bytes per pad
}

View file

@ -4,6 +4,16 @@
#pragma once
#include <SFML/Network/Packet.hpp>
#include <array>
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Timer.h"
@ -11,22 +21,13 @@
#include "Core/NetPlayProto.h"
#include "Core/Slippi/SlippiPad.h"
#include "InputCommon/GCPadStatus.h"
#include <SFML/Network/Packet.hpp>
#include <array>
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <queue>
#ifdef _WIN32
#include <Qos2.h>
#endif
#define SLIPPI_ONLINE_LOCKSTEP_INTERVAL 30 // Number of frames to wait before attempting to time-sync
#define SLIPPI_ONLINE_LOCKSTEP_INTERVAL \
30 // Number of frames to wait before attempting to time-sync
#define SLIPPI_PING_DISPLAY_INTERVAL 60
struct SlippiRemotePadOutput
@ -104,7 +105,8 @@ public:
void SendAsync(std::unique_ptr<sf::Packet> packet);
SlippiNetplayClient(bool isDecider); // Make a dummy client
SlippiNetplayClient(const std::string& address, const u16 remotePort, const u16 localPort, bool isDecider);
SlippiNetplayClient(const std::string& address, const u16 remotePort, const u16 localPort,
bool isDecider);
~SlippiNetplayClient();
// Slippi Online

View file

@ -15,4 +15,3 @@ public:
int32_t frame;
u8 padBuf[SLIPPI_PAD_FULL_SIZE];
};

View file

@ -86,8 +86,7 @@ void SlippiPlaybackStatus::prepareSlippiPlayback(s32& frameIndex)
// TODO: figure out why sometimes playback frame increments past targetFrameNum
if (inSlippiPlayback && frameIndex >= targetFrameNum)
{
INFO_LOG(SLIPPI, "Reached frame %d. Target was %d. Unblocking", frameIndex,
targetFrameNum);
INFO_LOG(SLIPPI, "Reached frame %d. Target was %d. Unblocking", frameIndex, targetFrameNum);
cv_waitingForTargetFrame.notify_one();
}
}
@ -136,7 +135,8 @@ void SlippiPlaybackStatus::SavestateThread()
{
// Wait to hit one of the intervals
// Possible while rewinding that we hit this wait again.
while (shouldRunThreads && (currentPlaybackFrame - Slippi::PLAYBACK_FIRST_SAVE) % FRAME_INTERVAL != 0)
while (shouldRunThreads &&
(currentPlaybackFrame - Slippi::PLAYBACK_FIRST_SAVE) % FRAME_INTERVAL != 0)
condVar.wait(intervalLock);
if (!shouldRunThreads)
@ -169,11 +169,13 @@ void SlippiPlaybackStatus::SavestateThread()
void SlippiPlaybackStatus::seekToFrame()
{
if (seekMtx.try_lock()) {
if (seekMtx.try_lock())
{
if (targetFrameNum < Slippi::PLAYBACK_FIRST_SAVE)
targetFrameNum = Slippi::PLAYBACK_FIRST_SAVE;
if (targetFrameNum > lastFrame) {
if (targetFrameNum > lastFrame)
{
targetFrameNum = lastFrame;
}
@ -186,8 +188,10 @@ void SlippiPlaybackStatus::seekToFrame()
if (prevState != Core::State::Paused)
Core::SetState(Core::State::Paused);
s32 closestStateFrame = targetFrameNum - emod(targetFrameNum - Slippi::PLAYBACK_FIRST_SAVE, FRAME_INTERVAL);
bool isLoadingStateOptimal = targetFrameNum < currentPlaybackFrame || closestStateFrame > currentPlaybackFrame;
s32 closestStateFrame =
targetFrameNum - emod(targetFrameNum - Slippi::PLAYBACK_FIRST_SAVE, FRAME_INTERVAL);
bool isLoadingStateOptimal =
targetFrameNum < currentPlaybackFrame || closestStateFrame > currentPlaybackFrame;
if (isLoadingStateOptimal)
{
@ -217,7 +221,8 @@ void SlippiPlaybackStatus::seekToFrame()
futureDiffs.count(closestActualStateFrame) == 0)
closestActualStateFrame -= FRAME_INTERVAL;
// only load a savestate if we find one past our current frame since we are seeking forwards
// only load a savestate if we find one past our current frame since we are seeking
// forwards
if (closestActualStateFrame > currentPlaybackFrame)
loadState(closestActualStateFrame);
}
@ -234,18 +239,22 @@ void SlippiPlaybackStatus::seekToFrame()
setHardFFW(false);
}
// We've reached the frame we want. Reset targetFrameNum and release mutex so another seek can be performed
// We've reached the frame we want. Reset targetFrameNum and release mutex so another seek can
// be performed
g_playbackStatus->currentPlaybackFrame = targetFrameNum;
targetFrameNum = INT_MAX;
Core::SetState(prevState);
seekMtx.unlock();
} else {
}
else
{
INFO_LOG(SLIPPI, "Already seeking. Ignoring this call");
}
}
// Set isHardFFW and update OC settings to speed up the FFW
void SlippiPlaybackStatus::setHardFFW(bool enable) {
void SlippiPlaybackStatus::setHardFFW(bool enable)
{
if (enable)
{
SConfig::GetInstance().m_OCEnable = true;
@ -260,7 +269,6 @@ void SlippiPlaybackStatus::setHardFFW(bool enable) {
isHardFFW = enable;
}
void SlippiPlaybackStatus::loadState(s32 closestStateFrame)
{
if (closestStateFrame == Slippi::PLAYBACK_FIRST_SAVE)
@ -268,7 +276,8 @@ void SlippiPlaybackStatus::loadState(s32 closestStateFrame)
else
{
std::string stateString;
decoder.Decode((char*)iState.data(), iState.size(), futureDiffs[closestStateFrame].get(), &stateString);
decoder.Decode((char*)iState.data(), iState.size(), futureDiffs[closestStateFrame].get(),
&stateString);
std::vector<u8> stateToLoad(stateString.begin(), stateString.end());
State::LoadFromBuffer(stateToLoad);
}

View file

@ -5,12 +5,12 @@
#include <unordered_map>
#include <vector>
#include <SlippiLib/SlippiGame.h>
#include <open-vcdiff/src/google/vcdecoder.h>
#include <open-vcdiff/src/google/vcencoder.h>
#include <SlippiLib/SlippiGame.h>
#include "Core/ConfigManager.h"
#include "../../Common/CommonTypes.h"
#include "Core/ConfigManager.h"
class SlippiPlaybackStatus
{

View file

@ -1,6 +1,6 @@
#include "SlippiReplayComm.h"
#include <cctype>
#include <memory>
#include "SlippiReplayComm.h"
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/Logging/LogManager.h"
@ -18,7 +18,8 @@ static inline void ltrim(std::string& s)
// trim from end (in place)
static inline void rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(),
s.end());
}
// trim from both ends (in place)
@ -35,7 +36,9 @@ SlippiReplayComm::SlippiReplayComm()
configFilePath = SConfig::GetInstance().m_strSlippiInput.c_str();
}
SlippiReplayComm::~SlippiReplayComm() {}
SlippiReplayComm::~SlippiReplayComm()
{
}
SlippiReplayComm::CommSettings SlippiReplayComm::getSettings()
{
@ -177,8 +180,8 @@ void SlippiReplayComm::loadFile()
{
WARN_LOG(EXPANSIONINTERFACE, "Comm file load error detected. Check file format");
// Reset in the case of read error. this fixes a race condition where file mod time changes but
// the file is not readable yet?
// Reset in the case of read error. this fixes a race condition where file mod time changes
// but the file is not readable yet?
configLastLoadModTime = 0;
}

View file

@ -1,10 +1,10 @@
#pragma once
#include <SlippiGame.h>
#include <limits.h>
#include <nlohmann/json.hpp>
#include <queue>
#include <string>
#include <nlohmann/json.hpp>
#include <SlippiGame.h>
#include <Common/CommonTypes.h>

View file

@ -1,4 +1,5 @@
#include "SlippiSavestate.h"
#include <vector>
#include "Common/CommonFuncs.h"
#include "Common/MemoryUtil.h"
#include "Core/HW/AudioInterface.h"
@ -11,7 +12,6 @@
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/SI/SI.h"
#include "Core/HW/VideoInterface.h"
#include <vector>
SlippiSavestate::SlippiSavestate()
{

View file

@ -1,8 +1,8 @@
#pragma once
#include <unordered_map>
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include <unordered_map>
class PointerWrap;
@ -14,7 +14,10 @@ public:
u32 address;
u32 length;
bool operator==(const PreserveBlock& p) const { return address == p.address && length == p.length; }
bool operator==(const PreserveBlock& p) const
{
return address == p.address && length == p.length;
}
};
SlippiSavestate();

View file

@ -110,19 +110,21 @@ bool SlippiUser::AttemptLogin()
{
std::string userFilePathTxt =
userFilePath + ".txt"; // Put the filename here in its own scope because we don't really need it elsewhere
userFilePath +
".txt"; // Put the filename here in its own scope because we don't really need it elsewhere
if (File::Exists(userFilePathTxt))
{
// If both files exist we just log they exist and take no further action
if (File::Exists(userFilePath))
{
INFO_LOG(SLIPPI_ONLINE,
"Found both .json.txt and .json file for user data. Using .json and ignoring the .json.txt");
INFO_LOG(SLIPPI_ONLINE, "Found both .json.txt and .json file for user data. Using .json "
"and ignoring the .json.txt");
}
// If only the .txt file exists move the contents to a json file and log if it fails
else if (!File::Rename(userFilePathTxt, userFilePath))
{
WARN_LOG(SLIPPI_ONLINE, "Could not move file %s to %s", userFilePathTxt.c_str(), userFilePath.c_str());
WARN_LOG(SLIPPI_ONLINE, "Could not move file %s to %s", userFilePathTxt.c_str(),
userFilePath.c_str());
}
}
}
@ -137,7 +139,8 @@ bool SlippiUser::AttemptLogin()
if (isLoggedIn)
{
overwriteFromServer();
WARN_LOG(SLIPPI_ONLINE, "Found user %s (%s)", userInfo.displayName.c_str(), userInfo.uid.c_str());
WARN_LOG(SLIPPI_ONLINE, "Found user %s (%s)", userInfo.displayName.c_str(),
userInfo.uid.c_str());
}
return isLoggedIn;
@ -149,7 +152,8 @@ void SlippiUser::OpenLogInPage()
std::string path = getUserFilePath();
#ifdef _WIN32
// On windows, sometimes the path can have backslashes and slashes mixed, convert all to backslashes
// On windows, sometimes the path can have backslashes and slashes mixed, convert all to
// backslashes
path = ReplaceAll(path, "\\", "\\");
path = ReplaceAll(path, "/", "\\");
#endif
@ -181,12 +185,15 @@ void SlippiUser::UpdateApp()
auto isoPath = SConfig::GetInstance().m_strIsoPath;
std::string path = File::GetExeDirectory() + "/dolphin-slippi-tools.exe";
std::string echoMsg = "echo Starting update process. If nothing happen after a few "
std::string echoMsg =
"echo Starting update process. If nothing happen after a few "
"minutes, you may need to update manually from https://slippi.gg/netplay ...";
// std::string command =
// "start /b cmd /c " + echoMsg + " && \"" + path + "\" app-update -launch -iso \"" + isoPath + "\"";
std::string command = "start /b cmd /c " + echoMsg + " && \"" + path + "\" app-update -launch -iso \"" + isoPath +
"\" -version \"" + Common::scm_slippi_semver_str + "\"";
// "start /b cmd /c " + echoMsg + " && \"" + path + "\" app-update -launch -iso \"" + isoPath +
// "\"";
std::string command = "start /b cmd /c " + echoMsg + " && \"" + path +
"\" app-update -launch -iso \"" + isoPath + "\" -version \"" +
Common::scm_slippi_semver_str + "\"";
WARN_LOG(SLIPPI, "Executing app update command: %s", command.c_str());
RunSystemCommand(command);
#elif defined(__APPLE__)
@ -263,7 +270,8 @@ void SlippiUser::FileListenThread()
std::string SlippiUser::getUserFilePath()
{
#if defined(__APPLE__)
std::string userFilePath = File::GetBundleDirectory() + "/Contents/Resources" + DIR_SEP + "user.json";
std::string userFilePath =
File::GetBundleDirectory() + "/Contents/Resources" + DIR_SEP + "user.json";
#elif defined(_WIN32)
std::string userFilePath = File::GetExeDirectory() + DIR_SEP + "user.json";
#else

View file

@ -1,12 +1,12 @@
#pragma once
#include "Common/CommonTypes.h"
#include <atomic>
#include <curl/curl.h>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include "Common/CommonTypes.h"
class SlippiUser
{

View file

@ -101,10 +101,11 @@ void SlippiPane::CreateLayout()
layout->addWidget(playback_settings);
auto* enable_playback_seek_checkbox = new QCheckBox(tr("Enable Seekbar"));
char seekbarTooltip[] = "<html><head/><body><p>Enables video player style controls while watching Slippi replays. Uses more cpu resources and can be stuttery. " \
"Space: Pause/Play " \
"Left/Right: Jump 5 seconds back/forward" \
"Shift + Left/Right: Jump 20 seconds back/forward" \
char seekbarTooltip[] = "<html><head/><body><p>Enables video player style controls while "
"watching Slippi replays. Uses more cpu resources and can be stuttery. "
"Space: Pause/Play "
"Left/Right: Jump 5 seconds back/forward"
"Shift + Left/Right: Jump 20 seconds back/forward"
"Period (while paused): Advance one frame";
enable_playback_seek_checkbox->setToolTip(tr(seekbarTooltip));
playback_settings_layout->addWidget(enable_playback_seek_checkbox);