mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-22 10:19:01 +00:00
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:
commit
a557edb283
21 changed files with 1616 additions and 1419 deletions
210
Externals/SlippiLib/SlippiGame.cpp
vendored
210
Externals/SlippiLib/SlippiGame.cpp
vendored
|
@ -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
|
||||
|
|
44
Externals/SlippiLib/SlippiGame.h
vendored
44
Externals/SlippiLib/SlippiGame.h
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,4 +15,3 @@ public:
|
|||
int32_t frame;
|
||||
u8 padBuf[SLIPPI_PAD_FULL_SIZE];
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue