Merge pull request #69 from r2dliu/port-pr/247

Port custom bootloader
This commit is contained in:
Nikhil Narayana 2021-12-12 16:43:15 -08:00 committed by GitHub
commit a2f24e8960
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 4606 additions and 2137 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

BIN
Data/Sys/bootloader.gct Normal file

Binary file not shown.

View file

@ -128,6 +128,7 @@
#define WII_SETTING "setting.txt"
#define GECKO_CODE_HANDLER "codehandler.bin"
#define GCT_BOOTLOADER "bootloader.gct"
// Subdirs in Sys
#define GC_SYS_DIR "GC"

View file

@ -26,13 +26,13 @@
#ifdef _WIN32
#include <windows.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <commdlg.h> // for GetSaveFileName
#include <direct.h> // getcwd
#include <io.h>
#include <objbase.h> // guid stuff
#include <shellapi.h>
#include <ShlObj.h>
#include <winerror.h>
#else
#include <dirent.h>
@ -791,21 +791,22 @@ std::string GetExePath()
return dolphin_path;
}
// SLIPPITODO: refactor with c++17 std::filesystem?
std::string GetHomeDirectory()
{
std::string homeDir;
#ifdef _WIN32
wchar_t* path = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &path))) {
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &path)))
{
char pathStr[MAX_PATH];
wcstombs(pathStr, path, MAX_PATH);
homeDir = std::string(pathStr);
CoTaskMemFree(path);
}
else {
else
{
const char* home = getenv("USERPROFILE");
homeDir = std::string(home) + "\\Documents";
}
@ -853,13 +854,15 @@ std::string GetSysDirectory()
ASSERT_MSG(COMMON, !sysDir.empty(), "Sys directory has not been set");
#else
const char* home = getenv("HOME");
if (!home) home = getenv("PWD");
if (!home) home = "";
if (!home)
home = getenv("PWD");
if (!home)
home = "";
std::string home_path = std::string(home) + DIR_SEP;
const char* config_home = getenv("XDG_CONFIG_HOME");
sysDir = std::string(config_home && config_home[0] == '/'
? config_home : (home_path + ".config"))
+ DIR_SEP DOLPHIN_DATA_DIR DIR_SEP "Sys" DIR_SEP;
sysDir =
std::string(config_home && config_home[0] == '/' ? config_home : (home_path + ".config")) +
DIR_SEP DOLPHIN_DATA_DIR DIR_SEP "Sys" DIR_SEP;
#endif
INFO_LOG_FMT(COMMON, "GetSysDirectory: Setting to {}:", sysDir);

View file

@ -41,6 +41,7 @@ namespace fs = std::filesystem;
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigManager.h"
#include "Core/FifoPlayer/FifoPlayer.h"
#include "Core/GeckoCode.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/EXI/EXI_DeviceIPL.h"
@ -537,6 +538,7 @@ bool CBoot::BootUp(std::unique_ptr<BootParameters> boot)
PatchEngine::LoadPatches();
HLE::PatchFixedFunctions();
Gecko::RunCodeHandler();
return true;
}

View file

@ -51,6 +51,7 @@
#include "VideoCommon/HiresTextures.h"
#include "DiscIO/Enums.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"
#include "DiscIO/VolumeWad.h"
@ -959,7 +960,32 @@ bool SConfig::SetPathsAndGameMetadata(const BootParameters& boot)
const std::string region_dir = GetDirectoryForRegion(ToGameCubeRegion(m_region));
m_strSRAM = File::GetUserPath(F_GCSRAM_IDX);
m_strBootROM = GetBootROMPath(region_dir);
m_strIsoPath = (boot.parameters.index() == 0) ? std::get<BootParameters::Disc>(boot.parameters).path : "";
m_strIsoPath =
(boot.parameters.index() == 0) ? std::get<BootParameters::Disc>(boot.parameters).path : "";
std::shared_ptr<DiscIO::Volume> volume = DiscIO::CreateVolume(m_strIsoPath);
if (m_game_id == "GALE01" || m_game_id == "GALJ01")
{
m_melee_version = Melee::Version::NTSC;
if (volume->GetLongNames()[DiscIO::Language::English].find("20XX") != std::string::npos)
m_melee_version = Melee::Version::TwentyXX;
else
{
// check for m-ex based build
if (volume->FileExists("MxDt.dat"))
{
m_melee_version = Melee::Version::MEX;
}
}
}
else if (m_game_id == "GTME01")
{
m_melee_version = Melee::Version::UPTM;
}
INFO_LOG_FMT(BOOT, "Melee Version: {}", m_melee_version);
return true;
}

View file

@ -4,6 +4,7 @@
#pragma once
#include <future>
#include <limits>
#include <optional>
#include <set>
@ -45,6 +46,18 @@ namespace SerialInterface
enum SIDevices : int;
} // namespace SerialInterface
namespace Melee
{
enum class Version
{
NTSC,
TwentyXX,
UPTM,
MEX,
OTHER,
};
}
struct BootParameters;
// DSP Backend Types
@ -67,6 +80,8 @@ enum class GPUDeterminismMode
struct SConfig
{
// Melee Version
Melee::Version m_melee_version;
// Wii Devices
bool m_WiiSDCard;
bool m_WiiKeyboard;

View file

@ -19,6 +19,8 @@
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "VideoCommon/OnScreenDisplay.h"
namespace Gecko
{
static constexpr u32 CODE_SIZE = 8;
@ -68,6 +70,8 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
{
std::lock_guard<std::mutex> lk(s_active_codes_lock);
DEBUG_LOG_FMT(ACTIONREPLAY, "Setting up active codes...");
s_active_codes.clear();
if (SConfig::GetInstance().bEnableCheats)
{
@ -153,32 +157,39 @@ static Installation InstallCodeHandlerLocked()
}
}
u32 codelist_base_address;
u32 codelist_end_address;
// Let the Gecko codehandler use free space from Melee's tournament mode region
if (SConfig::GetInstance().GetGameID() == "GALE01")
u32 codelist_base_address = INSTALLER_BASE_ADDRESS + static_cast<u32>(data.length()) - CODE_SIZE;
u32 codelist_end_address = INSTALLER_END_ADDRESS;
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
PowerPC::HostWrite_U32(MAGIC_GAMEID, INSTALLER_BASE_ADDRESS);
// Install the custom bootloader to write gecko codes to the heaps
if (SConfig::GetInstance().m_melee_version == Melee::Version::NTSC ||
SConfig::GetInstance().m_melee_version == Melee::Version::MEX)
{
INFO_LOG(ACTIONREPLAY,
"Detected GALE01 - using tournament mode region for Gecko codelist");
// Write GCT loader into memory which will eventually load the real GCT into the heap
std::string bootloaderData;
std::string _bootloaderFilename = File::GetSysDirectory() + GCT_BOOTLOADER;
if (!File::ReadFileToString(_bootloaderFilename, bootloaderData))
{
OSD::AddMessage("bootloader.gct not found in Sys folder.", 30000, 0xFFFF0000);
ERROR_LOG_FMT(ACTIONREPLAY, "Could not enable cheats because bootloader.gct was missing.");
return Installation::Failed;
}
// Set codelist base to the tournament mode region
codelist_base_address = 0x801910E0;
codelist_end_address = 0x8019AF4C;
if (bootloaderData.length() > codelist_end_address - codelist_base_address)
{
OSD::AddMessage("Gecko bootloader too large.", 30000, 0xFFFF0000);
ERROR_LOG_FMT(SLIPPI, "Gecko bootloader too large");
return Installation::Failed;
}
// Patch codehandler to use tournament mode region
PowerPC::HostWrite_U32(0x3DE08019, 0x80001904); // lis r15, 0x8019
PowerPC::HostWrite_U32(0x61EF10E0, 0x80001908); // ori r15, r15, 0x10e0
// Install bootloader gct
for (size_t i = 0; i < bootloaderData.length(); ++i)
PowerPC::HostWrite_U8(bootloaderData[i], static_cast<u32>(codelist_base_address + i));
}
else
{
codelist_base_address = INSTALLER_BASE_ADDRESS + static_cast<u32>(data.size()) - CODE_SIZE;
codelist_end_address = INSTALLER_END_ADDRESS;
}
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
PowerPC::HostWrite_U32(MAGIC_GAMEID, INSTALLER_BASE_ADDRESS);
// Create GCT in memory
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address);
PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4);
@ -194,6 +205,11 @@ static Installation InstallCodeHandlerLocked()
// If the code is not going to fit in the space we have left then we have to skip it
if (next_address + active_code.codes.size() * CODE_SIZE > end_address)
{
OSD::AddMessage(
fmt::format("Ran out of memory applying gecko codes. Too many codes enabled. "
"Need {} bytes, only {} remain.",
active_code.codes.size() * CODE_SIZE, end_address - next_address),
30000, 0xFFFF0000);
NOTICE_LOG_FMT(ACTIONREPLAY,
"Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
@ -216,6 +232,9 @@ static Installation InstallCodeHandlerLocked()
// Stop code. Tells the handler that this is the end of the list.
PowerPC::HostWrite_U32(0xF0000000, next_address);
PowerPC::HostWrite_U32(0x00000000, next_address + 4);
}
// Write 0 to trampoline address, not sure why this is necessary
PowerPC::HostWrite_U32(0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes
@ -226,6 +245,7 @@ static Installation InstallCodeHandlerLocked()
{
PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j);
}
return Installation::Installed;
}
@ -296,10 +316,73 @@ void RunCodeHandler()
}
DEBUG_LOG_FMT(ACTIONREPLAY,
"GeckoCodes: Initiating phantom branch-and-link. "
"PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}",
"PC = {:#010x}, SP = {:#010x}, SFP = {:#010x}\n",
PC, SP, SFP);
LR = HLE_TRAMPOLINE_ADDRESS;
PC = NPC = ENTRY_POINT;
}
u32 GetGctLength()
{
std::lock_guard<std::mutex> lk(s_active_codes_lock);
int i = 0;
for (const GeckoCode& active_code : s_active_codes)
{
if (active_code.enabled)
{
i += 8 * static_cast<int>(active_code.codes.size());
}
}
return i + 0x10; // 0x10 is the fixed size of the header and terminator
}
std::vector<u8> uint32ToVector(u32 num)
{
u8 byte0 = num >> 24;
u8 byte1 = (num & 0xFF0000) >> 16;
u8 byte2 = (num & 0xFF00) >> 8;
u8 byte3 = num & 0xFF;
return std::vector<u8>({byte0, byte1, byte2, byte3});
}
void appendWordToBuffer(std::vector<u8>* buf, u32 word)
{
auto wordVector = uint32ToVector(word);
buf->insert(buf->end(), wordVector.begin(), wordVector.end());
}
std::vector<u8> GenerateGct()
{
std::vector<u8> res;
// Write header
appendWordToBuffer(&res, 0x00d0c0de);
appendWordToBuffer(&res, 0x00d0c0de);
std::lock_guard<std::mutex> lk(s_active_codes_lock);
// Write codes
for (const GeckoCode& active_code : s_active_codes)
{
if (active_code.enabled)
{
for (const GeckoCode::Code& code : active_code.codes)
{
appendWordToBuffer(&res, code.address);
appendWordToBuffer(&res, code.data);
}
}
}
// Write footer
appendWordToBuffer(&res, 0xff000000);
appendWordToBuffer(&res, 0x00000000);
return res;
}
} // namespace Gecko

View file

@ -66,4 +66,7 @@ void RunCodeHandler();
void Shutdown();
void DoState(PointerWrap&);
u32 GetGctLength();
std::vector<u8> GenerateGct();
} // namespace Gecko

View file

@ -20,11 +20,13 @@
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/GeckoCode.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/PowerPC/PowerPC.h"
#include "Core/Slippi/SlippiPlayback.h"
#include "Core/Slippi/SlippiReplayComm.h"
#include "Core/State.h"
@ -95,6 +97,18 @@ void appendHalfToBuffer(std::vector<u8>* buf, u16 word)
buf->insert(buf->end(), halfVector.begin(), halfVector.end());
}
std::string ConvertConnectCodeForGame(const std::string& input)
{
// Shift-Jis '#' symbol is two bytes (0x8194), followed by 0x00 null terminator
char fullWidthShiftJisHashtag[] = {-127, -108, 0}; // 0x81, 0x94, 0x00
std::string connectCode(input);
// SLIPPITODONot the best use of ReplaceAll. potential bug if more than one '#' found.
connectCode = ReplaceAll(connectCode, "#", std::string(fullWidthShiftJisHashtag));
connectCode.resize(CONNECT_CODE_LENGTH +
2); // fixed length + full width (two byte) hashtag +1, null terminator +1
return connectCode;
}
CEXISlippi::CEXISlippi()
{
INFO_LOG(SLIPPI, "EXI SLIPPI Constructor called.");
@ -1484,8 +1498,7 @@ bool CEXISlippi::isDisconnected()
return true;
auto status = slippi_netplay->GetSlippiConnectStatus();
return status != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED ||
isConnectionStalled;
return status != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED;
}
static int tempTestCount = 0;
@ -2100,16 +2113,6 @@ void CEXISlippi::prepareOnlineMatchState()
// Set p3/p4 player type to human
onlineMatchBlock[0x61 + 2 * 0x24] = 0;
onlineMatchBlock[0x61 + 3 * 0x24] = 0;
// Set alt color to light/dark costume for multiples of the same character on a team
int characterCount[26][3] = {0};
for (int i = 0; i < 4; i++)
{
int charId = onlineMatchBlock[0x60 + i * 0x24];
int teamId = onlineMatchBlock[0x69 + i * 0x24];
onlineMatchBlock[0x67 + i * 0x24] = characterCount[charId][teamId];
characterCount[charId][teamId]++;
}
}
// Overwrite stage
@ -2133,7 +2136,7 @@ void CEXISlippi::prepareOnlineMatchState()
onlineMatchBlock[0x84]);
// Turn pause on in direct, off in everything else
u8* gameBitField3 = (u8*)&onlineMatchBlock[2];
u8* gameBitField3 = static_cast<u8*>(&onlineMatchBlock[2]);
*gameBitField3 = lastSearch.mode >= directMode ? *gameBitField3 & 0xF7 : *gameBitField3 | 0x8;
//*gameBitField3 = *gameBitField3 | 0x8;
@ -2146,8 +2149,8 @@ void CEXISlippi::prepareOnlineMatchState()
else
rightTeamPlayers.push_back(i);
}
auto leftTeamSize = leftTeamPlayers.size();
auto rightTeamSize = rightTeamPlayers.size();
int leftTeamSize = static_cast<int>(leftTeamPlayers.size());
int rightTeamSize = static_cast<int>(rightTeamPlayers.size());
leftTeamPlayers.resize(4, 0);
rightTeamPlayers.resize(4, 0);
leftTeamPlayers[3] = static_cast<u8>(leftTeamSize);
@ -2211,6 +2214,21 @@ void CEXISlippi::prepareOnlineMatchState()
oppName = ConvertStringForGame(oppText, MAX_NAME_LENGTH * 2 + 1);
m_read_queue.insert(m_read_queue.end(), oppName.begin(), oppName.end());
#ifdef LOCAL_TESTING
std::string defaultConnectCodes[] = {"PLYR#001", "PLYR#002", "PLYR#003", "PLYR#004"};
#endif
auto playerInfo = matchmaking->GetPlayerInfo();
for (int i = 0; i < 4; i++)
{
std::string connectCode = i < playerInfo.size() ? playerInfo[i].connect_code : "";
#ifdef LOCAL_TESTING
connectCode = defaultConnectCodes[i];
#endif
connectCode = ConvertConnectCodeForGame(connectCode);
m_read_queue.insert(m_read_queue.end(), connectCode.begin(), connectCode.end());
}
// Add error message if there is one
auto errorStr = !forcedError.empty() ? forcedError : matchmaking->GetErrorMessage();
errorStr = ConvertStringForGame(errorStr, 120);
@ -2317,6 +2335,32 @@ void CEXISlippi::prepareFileLoad(u8* payload)
m_read_queue.insert(m_read_queue.end(), buf.begin(), buf.end());
}
void CEXISlippi::prepareGctLength()
{
m_read_queue.clear();
u32 size = Gecko::GetGctLength();
INFO_LOG(SLIPPI, "Getting gct size: %d", size);
// Write size to output
appendWordToBuffer(&m_read_queue, size);
}
void CEXISlippi::prepareGctLoad(u8* payload)
{
m_read_queue.clear();
auto gct = Gecko::GenerateGct();
// This is the address where the codes will be written to
auto address = Common::swap32(&payload[0]);
INFO_LOG(SLIPPI, "Preparing to write gecko codes at: 0x%X", address);
m_read_queue.insert(m_read_queue.end(), gct.begin(), gct.end());
}
void CEXISlippi::handleChatMessage(u8* payload)
{
int messageId = payload[0];
@ -2468,6 +2512,7 @@ void CEXISlippi::prepareNewSeed()
void CEXISlippi::handleReportGame(u8* payload)
{
#ifndef LOCAL_TESTING
SlippiGameReporter::GameReport r;
r.duration_frames = Common::swap32(&payload[0]);
@ -2488,6 +2533,7 @@ void CEXISlippi::handleReportGame(u8* payload)
}
game_reporter->StartReport(r);
#endif
}
void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
@ -2619,6 +2665,12 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
case CMD_REPORT_GAME:
handleReportGame(&memPtr[bufLoc + 1]);
break;
case CMD_GCT_LENGTH:
prepareGctLength();
break;
case CMD_GCT_LOAD:
prepareGctLoad(&memPtr[bufLoc + 1]);
break;
default:
writeToFileAsync(&memPtr[bufLoc], payloadLen + 1, "");
SlippiSpectateServer::getInstance().write(&memPtr[bufLoc], payloadLen + 1);

View file

@ -10,6 +10,7 @@
#include "Common/File.h"
#include "Common/FileUtil.h"
#include "Core/Slippi/SlippiGameFileLoader.h"
#include "Core/Slippi/SlippiGameReporter.h"
#include "Core/Slippi/SlippiMatchmaking.h"
#include "Core/Slippi/SlippiNetplay.h"
#include "Core/Slippi/SlippiPlayback.h"
@ -17,7 +18,6 @@
#include "Core/Slippi/SlippiSavestate.h"
#include "Core/Slippi/SlippiSpectate.h"
#include "Core/Slippi/SlippiUser.h"
#include "Core/Slippi/SlippiGameReporter.h"
#include "EXI_Device.h"
#define ROLLBACK_MAX_FRAMES 7
@ -79,6 +79,8 @@ private:
CMD_LOG_MESSAGE = 0xD0,
CMD_FILE_LENGTH = 0xD1,
CMD_FILE_LOAD = 0xD2,
CMD_GCT_LENGTH = 0xD3,
CMD_GCT_LOAD = 0xD4,
};
enum
@ -124,6 +126,8 @@ private:
{CMD_LOG_MESSAGE, 0xFFFF}, // Variable size... will only work if by itself
{CMD_FILE_LENGTH, 0x40},
{CMD_FILE_LOAD, 0x40},
{CMD_GCT_LENGTH, 0x0},
{CMD_GCT_LOAD, 0x4},
};
struct WriteMessage
@ -189,6 +193,8 @@ private:
void logMessageFromGame(u8* payload);
void prepareFileLength(u8* payload);
void prepareFileLoad(u8* payload);
void prepareGctLength();
void prepareGctLoad(u8* payload);
int getCharColor(u8 charId, u8 teamId);
void FileWriteThread(void);

View file

@ -77,7 +77,7 @@ CoreTiming::EventType* et_AudioDMA;
CoreTiming::EventType* et_DSP;
CoreTiming::EventType* et_IPC_HLE;
// PatchEngine updates every 1/60th of a second by default
CoreTiming::EventType* et_PatchEngine;
// CoreTiming::EventType* et_PatchEngine;
CoreTiming::EventType* et_Throttle;
u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!)
@ -163,7 +163,7 @@ void PatchEngineCallback(u64 userdata, s64 cycles_late)
cycles_pruned += next_schedule;
}
CoreTiming::ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned);
// CoreTiming::ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned);
}
void ThrottleCallback(u64 last_time, s64 cyclesLate)
@ -326,7 +326,7 @@ void Init()
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
// et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI);
@ -334,7 +334,7 @@ void Init()
CoreTiming::ScheduleEvent(s_audio_dma_period, et_AudioDMA);
CoreTiming::ScheduleEvent(0, et_Throttle, Common::Timer::GetTimeUs());
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine);
// CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine);
if (SConfig::GetInstance().bWii)
CoreTiming::ScheduleEvent(s_ipc_hle_period, et_IPC_HLE);

View file

@ -16,18 +16,6 @@
#include <json.hpp>
using json = nlohmann::json;
inline size_t receive(char* ptr, size_t size, size_t nmemb, void* rcvBuf)
{
size_t len = size * nmemb;
INFO_LOG(SLIPPI_ONLINE, "[User] Received data: %d", len);
std::string* buf = (std::string*)rcvBuf;
buf->insert(buf->end(), ptr, ptr + len);
return len;
}
SlippiGameReporter::SlippiGameReporter(SlippiUser* user)
{
CURL* curl = curl_easy_init();
@ -76,7 +64,7 @@ void SlippiGameReporter::StartReport(GameReport report)
void SlippiGameReporter::StartNewSession(std::vector<std::string> new_player_uids)
{
this->player_uids = new_player_uids;
this->m_player_uids = new_player_uids;
gameIndex = 1;
}
@ -108,7 +96,7 @@ void SlippiGameReporter::ReportThreadHandler()
for (int i = 0; i < report.players.size(); i++)
{
json p;
p["uid"] = player_uids[i];
p["uid"] = m_player_uids[i];
p["damage_done"] = report.players[i].damage_done;
p["stocks_remaining"] = report.players[i].stocks_remaining;

View file

@ -38,7 +38,7 @@ protected:
struct curl_slist* m_curl_header_list = nullptr;
u32 gameIndex = 1;
std::vector<std::string> player_uids;
std::vector<std::string> m_player_uids;
SlippiUser* m_user;
std::queue<GameReport> game_report_queue;

View file

@ -67,13 +67,13 @@ SlippiNetplayClient::SlippiNetplayClient(std::vector<std::string> addrs, std::ve
this->isDecider = isDecider;
this->m_remotePlayerCount = remotePlayerCount;
this->playerIdx = playerIdx;
this->m_player_idx = playerIdx;
// Set up remote player data structures.
int j = 0;
for (int i = 0; i < SLIPPI_REMOTE_PLAYER_MAX; i++, j++)
{
if (j == playerIdx)
if (j == m_player_idx)
j++;
this->matchInfo.remotePlayerSelections[i] = SlippiPlayerSelections();
this->matchInfo.remotePlayerSelections[i].playerIdx = j;
@ -151,7 +151,7 @@ SlippiNetplayClient::SlippiNetplayClient(bool isDecider)
u8 SlippiNetplayClient::PlayerIdxFromPort(u8 port)
{
u8 p = port;
if (port > playerIdx)
if (port > m_player_idx)
{
p--;
}
@ -160,7 +160,7 @@ u8 SlippiNetplayClient::PlayerIdxFromPort(u8 port)
u8 SlippiNetplayClient::LocalPlayerPort()
{
return this->playerIdx;
return this->m_player_idx;
}
// called from ---NETPLAY--- thread
@ -267,7 +267,7 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
sf::Packet spac;
spac << (NetPlay::MessageId)NetPlay::NP_MSG_SLIPPI_PAD_ACK;
spac << frame;
spac << playerIdx;
spac << m_player_idx;
INFO_LOG(SLIPPI_ONLINE, "Sending ack packet for frame %d (player %d) to peer at %d:%d", frame,
packetPlayerPort, peer->address.host, peer->address.port);
@ -835,7 +835,7 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<NetPlay::MessageId>(NetPlay::NP_MSG_SLIPPI_PAD);
*spac << frame;
*spac << this->playerIdx;
*spac << this->m_player_idx;
// INFO_LOG(SLIPPI_ONLINE, "Sending a packet of inputs [%d]...", frame);
for (auto it = localPadQueue.begin(); it != localPadQueue.end(); ++it)
{
@ -869,7 +869,7 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
void SlippiNetplayClient::SetMatchSelections(SlippiPlayerSelections& s)
{
matchInfo.localPlayerSelections.Merge(s);
matchInfo.localPlayerSelections.playerIdx = playerIdx;
matchInfo.localPlayerSelections.playerIdx = m_player_idx;
// Send packet containing selections
auto spac = std::make_unique<sf::Packet>();

View file

@ -192,7 +192,7 @@ protected:
bool isConnectionSelected = false;
bool isDecider = false;
bool hasGameStarted = false;
u8 playerIdx = 0;
u8 m_player_idx = 0;
std::deque<std::unique_ptr<SlippiPad>> localPadQueue; // most recent inputs at start of deque
std::deque<std::unique_ptr<SlippiPad>>

View file

@ -85,6 +85,26 @@ std::map<Language, std::string> Volume::ReadWiiNames(const std::vector<char16_t>
return names;
}
bool Volume::FileExists(std::string file_name)
{
std::vector<DiscIO::Partition> partitions = this->GetPartitions();
if (partitions.empty())
partitions.emplace_back(PARTITION_NONE);
for (const auto& partition : partitions)
{
const DiscIO::FileInfo& root_dir = this->GetFileSystem(partition)->GetRoot();
for (const auto& file_info : root_dir)
{
if (file_info.GetName() == file_name)
{
return true;
}
}
}
return false;
}
static std::unique_ptr<VolumeDisc> CreateDisc(std::unique_ptr<BlobReader>& reader)
{
// Check for Wii

View file

@ -152,6 +152,8 @@ public:
// The way the hash is calculated may change with updates to Dolphin.
virtual std::array<u8, 20> GetSyncHash() const = 0;
bool FileExists(std::string file_name);
protected:
template <u32 N>
std::string DecodeString(const char (&data)[N]) const